Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> n = n.getFirstChild(); } handleGet(t, n, parent, prefix, Ref.Type.PROTOTYPE_GET); return true; } /** * Determines whether an assignment is nested (i.e. whether its return * value is used). * * @param parent The parent of the current traversal node (not null) * @return Whether it appears that the return value of the assignment is * used */ boolean isNestedAssign(Node parent) { return parent.getType() == Token.ASSIGN && !NodeUtil.isExpressionNode(parent.getParent()); } /** * Gets a {@link Name} instance for a global name. Creates it if necessary, * as well as instances for any of its prefixes that are not yet defined. * * @param name A global name (e.g. "a", "a.b.c.d") * @return The {@link Name} instance for {@code name} */ Name getOrCreateName(String name) { Name node = nameMap.get(name); if (node == null) { int i = name.lastIndexOf('.'); if (i >= 0) { String parentName = name.substring(0, i); Name parent = getOrCreateName(parentName); node = parent.addProperty(name.substring(i + 1), inExterns); } else { node = new Name(name, null, inExterns); globalNames.add(node); } nameMap.put(name, node); } return node; } } // ------------------------------------------------------------------------- /** * A name defined in global scope (e.g. "a" or "a.b.c.d"). These form a tree. * As the parse tree traversal proceeds, we'll discover that some names * correspond to JavaScript objects whose properties we should consider * collapsing. */ static class Name { enum Type { OBJECTLIT, FUNCTION, OTHER, } final String name; final Name parent; List<Name> props; Ref declaration; List<Ref> refs; Type type; private boolean isClassOrEnum = false; private boolean hasClassOrEnumDescendant = false; int globalSets = 0; int

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> localSets = 0; int aliasingGets = 0; int totalGets = 0; int callGets = 0; boolean inExterns; JSDocInfo docInfo = null; Name(String name, Name parent, boolean inExterns) { this.name = name; this.parent = parent; this.type = Type.OTHER; this.inExterns = inExterns; } Name addProperty(String name, boolean inExterns) { if (props == null) { props = new ArrayList<Name>(); } Name node = new Name(name, this, inExterns); props.add(node); return node; } void addRef(Ref ref) { switch (ref.type) { case SET_FROM_GLOBAL: if (declaration == null) { declaration = ref; docInfo = getDocInfoForDeclaration(ref); } else { addRefInternal(ref); } globalSets++; break; case SET_FROM_LOCAL: addRefInternal(ref); localSets++; break; case PROTOTYPE_GET: case DIRECT_GET: addRefInternal(ref); totalGets++; break; case ALIASING_GET: addRefInternal(ref); aliasingGets++; totalGets++; break; case CALL_GET: addRefInternal(ref); callGets++; totalGets++; break; default: throw new IllegalStateException(); } } void removeRef(Ref ref) { if (ref == declaration || (refs != null && refs.remove(ref))) { if (ref == declaration) { declaration = null; if (refs != null) { for (Ref maybeNewDecl : refs) { if (maybeNewDecl.type == Ref.Type.SET_FROM_GLOBAL) { declaration = maybeNewDecl; refs.remove(declaration); break; } } } } switch (ref.type) { case SET_FROM_GLOBAL: globalSets--; break; case SET_FROM_LOCAL: localSets--; break; case PROTOTYPE_GET: case DIRECT_GET: totalGets--; break; case

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>getJSDocInfo() : ref.node.getJSDocInfo(); } } return null; } } // ------------------------------------------------------------------------- /** * A global name reference. Contains references to the relevant parse tree * node and its ancestors that may be affected. */ static class Ref { enum Type { SET_FROM_GLOBAL, SET_FROM_LOCAL, PROTOTYPE_GET, ALIASING_GET, // Prevents a name's properties from being collapsed DIRECT_GET, // Prevents a name from being completely eliminated CALL_GET, // Prevents a name from being collapsed if never set } Node node; final Type type; final String sourceName; final Scope scope; final JSModule module; /** * Certain types of references are actually double-refs. For example, * var a = b = 0; * counts as both a "set" of b and an "alias" of b. * * We create two Refs for this node, and mark them as twins of each other. */ private Ref twin = null; /** * Creates a reference at the current node. */ Ref(NodeTraversal t, Node name, Type type) { this.node = name; this.sourceName = t.getSourceName(); this.type = type; this.scope = t.getScope(); this.module = t.getModule(); } private Ref(Ref original, Type type) { this.node = original.node; this.sourceName = original.sourceName; this.type = type; this.scope = original.scope; this.module = original.module; } private Ref(Type type) { this.type = type; this.sourceName = "source"; this.scope = null; this.module = null; } Ref getTwin() { return twin; } boolean isSet() { return type == Type.SET_FROM_GLOBAL || type == Type.SET_FROM_LOCAL; } static void markTwins(Ref a, Ref b) { Preconditions.checkArgument( (a.type == Type.ALIASING_GET || b.type == Type.ALIASING_GET) && (a

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> normalized * later on by the SourceMap. * * @see SourceMap */ private static class Mapping { Node node; Position start; Position end; } /** * Starts the source mapping for the given * node at the current position. */ @Override void startSourceMapping(Node node) { if (createSrcMap && node.getProp(Node.SOURCEFILE_PROP) != null && node.getLineno() > 0) { int line = getCurrentLineIndex(); int index = getCurrentCharIndex(); // If the index is -1, we are not performing any mapping. if (index >= 0) { Mapping mapping = new Mapping(); mapping.node = node; mapping.start = new Position(line, index); mappings.push(mapping); allMappings.add(mapping); } } } /** * Finishes the source mapping for the given * node at the current position. */ @Override void endSourceMapping(Node node) { if (createSrcMap && node.getProp(Node.SOURCEFILE_PROP) != null && node.getLineno() > 0) { int line = getCurrentLineIndex(); int index = getCurrentCharIndex(); // If the index is -1, we are not performing any mapping. if (index >= 0) { Preconditions.checkState( !mappings.empty(), "Mismatch in start and end of mapping"); Mapping mapping = mappings.pop(); mapping.end = new Position(line, index); } } } /** * Generates the source map from the given code consumer, * appending the information it saved to the SourceMap * object given. */ @Override void generateSourceMap(SourceMap map){ if (createSrcMap) { for (Mapping mapping : allMappings) { map.addMapping(mapping.node, mapping.start, mapping.end); } } } /** * Reports to the code consumer that the given line has been cut at the * given position (i.e. a \n has been inserted there). All mappings in * the source maps after that position will be renormalized as needed. */ void reportLineCut(int lineIndex, int characterPosition) { if

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>); } } /** * Expect that the given variable has not been declared with a type. * * @param sourceName The name of the source file we're in. * @param n The node where warnings should point to. * @param parent The parent of {@code n}. * @param var The variable that we're checking. * @param variableName The name of the variable. * @param newType The type being applied to the variable. Mostly just here * for the benefit of the warning. */ void expectUndeclaredVariable(String sourceName, Node n, Node parent, Var var, String variableName, JSType newType) { boolean allowDupe = false; if (n.getType() == Token.GETPROP) { JSDocInfo info = n.getJSDocInfo(); if (info == null) { info = parent.getJSDocInfo(); } allowDupe = info != null && info.getSuppressions().contains("duplicate"); } JSType varType = var.getType(); // Only report duplicate declarations that have types. Other duplicates // will be reported by the syntactic scope creator later in the // compilation process. if (varType != null && varType != typeRegistry.getNativeType(UNKNOWN_TYPE) && newType != null && newType != typeRegistry.getNativeType(UNKNOWN_TYPE)) { // If there are two typed declarations of the same variable, that // is an error and the second declaration is ignored, except in the // case of native types. A null input type means that the declaration // was made in TypedScopeCreator#createInitialScope and is a // native type. if (var.input == null) { n.setJSType(varType); if (parent.getType() == Token.VAR) { if (n.getFirstChild() != null) { n.getFirstChild().setJSType(varType); } } else { Preconditions.checkState(parent.getType() == Token.FUNCTION); parent.setJSType(varType); } } else { // Always warn about duplicates if the overridden type does not // match the original type. // // If the types match, suppress the warning iff there was a @suppress //

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> tag, or if the original declaration was a stub. if (!(allowDupe || var.getParentNode().getType() == Token.EXPR_RESULT) || !newType.equals(varType)) { compiler.report( JSError.make(sourceName, n, DUP_VAR_DECLARATION, variableName, newType.toString(), var.getInputName(), String.valueOf(var.nameNode.getLineno()), varType.toString())); } } } } /** * Expect that all properties on interfaces that this type implements are * implemented. */ void expectAllInterfacePropertiesImplemented(FunctionType type) { ObjectType instance = type.getInstanceType(); for (ObjectType implemented : type.getAllImplementedInterfaces()) { if (implemented.getImplicitPrototype() != null) { for (String prop : implemented.getImplicitPrototype().getOwnPropertyNames()) { if (!instance.hasProperty(prop)) { Node source = type.getSource(); Preconditions.checkNotNull(source); String sourceName = (String) source.getProp(Node.SOURCENAME_PROP); sourceName = sourceName == null ? "" : sourceName; compiler.report(JSError.make(sourceName, source, INTERFACE_METHOD_NOT_IMPLEMENTED, prop, implemented.toString(), instance.toString())); registerMismatch(instance, implemented); } } } } } /** * Report a type mismatch */ private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSType required) { mismatch(t.getSourceName(), n, msg, found, required); } private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSTypeNative required) { mismatch(t, n, msg, found, getNativeType(required)); } private void mismatch(String sourceName, Node n, String msg, JSType found, JSType required) { registerMismatch(found, required); compiler.report( JSError.make(sourceName, n, TYPE_MISMATCH_WARNING, formatFoundRequired(msg, found, required))); } private void registerMismatch(JSType found, JSType required) { // Don't register a mismatch for differences in null or undefined or if the // code didn

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp.parsing; import com.google.common.base.Preconditions; import com.google.javascript.jscomp.mozilla.rhino.ScriptRuntime; /** * This class implements the scanner for JsDoc strings. * * It is heavily based on Rhino's TokenStream. * * */ class JsDocTokenStream { /* * For chars - because we need something out-of-range * to check. (And checking EOF by exception is annoying.) * Note distinction from EOF token type! */ private final static int EOF_CHAR = -1; JsDocTokenStream(String sourceString) { this(sourceString, 0); } JsDocTokenStream(String sourceString, int lineno) { this(sourceString, lineno, 0); } JsDocTokenStream(String sourceString, int lineno, int initCharno) { Preconditions.checkNotNull(sourceString); this.lineno = lineno; this.sourceString = sourceString; this.sourceEnd = sourceString.length(); this.sourceCursor = this.cursor = 0; this.initLineno = lineno; this.initCharno = initCharno; } /** * Tokenizes JSDoc comments. */ @SuppressWarnings("fallthrough") final JsDocToken getJsDocToken() { int c; stringBufferTop = 0; for (;;) { // eat white spaces for (;;) { charno = -1; c = getChar(); if (c == EOF_CHAR) { return JsDocToken.EOF;

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> the last value of * the @define. */ private static final class CollectDefines implements Callback { private final AbstractCompiler compiler; private final Map<String, DefineInfo> assignableDefines; private final Map<String, DefineInfo> allDefines; private final Map<Node, RefInfo> allRefInfo; // A hack that allows us to remove ASSIGN/VAR statements when // we're currently visiting one of the children of the assign. private Node lvalueToRemoveLater = null; // A stack tied to the node traversal, to keep track of whether // we're in a conditional block. If 1 is at the top, assignment to // a define is allowed. Otherwise, it's not allowed. // // TODO(user): Replace with ArrayDeque private final IntStack assignAllowed; CollectDefines(AbstractCompiler compiler, List<Name> listOfDefines) { this.compiler = compiler; this.allDefines = Maps.newHashMap(); assignableDefines = Maps.newHashMap(); assignAllowed = new IntStack(); assignAllowed.add(1); // Create a map of references to defines keyed by node for easy lookup allRefInfo = Maps.newHashMap(); for (Name name : listOfDefines) { if (name.declaration != null) { allRefInfo.put(name.declaration.node, new RefInfo(name.declaration, name)); } if (name.refs != null) { for (Ref ref : name.refs) { // If there's a TWIN def, only put one of the twins in. if (ref.getTwin() == null || !ref.getTwin().isSet()) { allRefInfo.put(ref.node, new RefInfo(ref, name)); } } } } } /** * Get a map of {@link DefineInfo} structures, keyed by the name of * the define. */ Map<String, DefineInfo> getAllDefines() { return allDefines; } /** * Keeps track of whether the traversal is in a conditional branch. * We traverse all nodes of the parse tree. */ public boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { updateAssignAllowedStack(n, true); return true; } public void visit

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>(NodeTraversal t, Node n, Node parent) { RefInfo refInfo = allRefInfo.get(n); if (refInfo != null) { Ref ref = refInfo.ref; Name name = refInfo.name; String fullName = name.fullName(); switch (ref.type) { case SET_FROM_GLOBAL: case SET_FROM_LOCAL: Node valParent = getValueParent(ref); Node val = valParent.getLastChild(); if (valParent.getType() == Token.ASSIGN && name.isSimpleName() && name.declaration == ref) { // For defines, it's an error if a simple name is assigned // before it's declared compiler.report( JSError.make(t, val, INVALID_DEFINE_INIT_ERROR, fullName)); } else if (processDefineAssignment(t, fullName, val, valParent)) { // remove the assignment so that the variable is still declared, // but no longer assigned to a value, e.g., // DEF_FOO = 5; // becomes "5;" // We can't remove the ASSIGN/VAR when we're still visiting its // children, so we'll have to come back later to remove it. refInfo.name.removeRef(ref); lvalueToRemoveLater = valParent; } break; default: if (t.inGlobalScope()) { // Treat this as a reference to a define in the global scope. // After this point, the define must not be reassigned, // or it's an error. DefineInfo info = assignableDefines.get(fullName); if (info != null) { setDefineInfoNotAssignable(info, t); assignableDefines.remove(fullName); } } break; } } if (!t.inGlobalScope() && n.getJSDocInfo() != null && n.getJSDocInfo().isDefine()) { // warn about @define annotations in local scopes compiler.report( JSError.make(t, n, NON_GLOBAL_DEFINE_INIT_ERROR, "")); } if (lvalueToRemoveLater == n) { lvalueToRemoveLater = null; if (n.getType() == Token.ASSIGN) { Node last = n.getLastChild(); n.

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>removeChild(last); parent.replaceChild(n, last); } else { Preconditions.checkState(n.getType() == Token.NAME); n.removeChild(n.getFirstChild()); } compiler.reportCodeChange(); } if (n.getType() == Token.CALL) { if (t.inGlobalScope()) { // If there's a function call in the global scope, // we just say it's unsafe and freeze all the defines. // // NOTE(nicksantos): We could be a lot smarter here. For example, // ReplaceOverriddenVars keeps a call graph of all functions and // which functions/variables that they reference, and tries // to statically determine which functions are "safe" and which // are not. But this would be overkill, expecially because // the intended use of defines is with config_files, where // all the defines are at the top of the bundle. for (DefineInfo info : assignableDefines.values()) { setDefineInfoNotAssignable(info, t); } assignableDefines.clear(); } } updateAssignAllowedStack(n, false); } /** * Determines whether assignment to a define should be allowed * in the subtree of the given node, and if not, records that fact. * * @param n The node whose subtree we're about to enter or exit. * @param entering True if we're entering the subtree, false otherwise. */ private void updateAssignAllowedStack(Node n, boolean entering) { switch (n.getType()) { case Token.CASE: case Token.FOR: case Token.FUNCTION: case Token.HOOK: case Token.IF: case Token.SWITCH: case Token.WHILE: if (entering) { assignAllowed.add(0); } else { assignAllowed.remove(); } break; } } /** * Determines whether assignment to a define should be allowed * at the current point of the traversal. */ private boolean isAssignAllowed() { return assignAllowed.element() == 1; } /** * Tracks the given define. * * @param t The current traversal, for context. * @param name The full name for this define. * @param value The

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>) cb; } this.compiler = compiler; this.sourceName = ""; this.scopeCreator = scopeCreator; } private void throwUnexpectedException(Exception unexpectedException) { // If there's an unexpected exception, try to get the // line number of the code that caused it. String message = unexpectedException.getMessage(); // TODO(user): It is possible to get more information if curNode or // its parent is missing. We still have the scope stack in which it is still // very useful to find out at least which function caused the exception. if (!sourceName.isEmpty()) { message = unexpectedException.getMessage() + "\n" + formatNodeContext("Node", curNode) + (curNode == null ? "" : formatNodeContext("Parent", curNode.getParent())); } compiler.throwInternalError(message, unexpectedException); } private String formatNodeContext(String label, Node n) { if (n == null) { return " " + label + ": NULL"; } return " " + label + "(" + n.toString(false, false, false) + "): " + formatNodePosition(n); } /** * Traverses a parse tree recursively. */ public void traverse(Node root) { try { sourceName = ""; curNode = root; pushScope(root); traverseBranch(root, null); popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException); } } public void traverseRoots(Node ... roots) { traverseRoots(Lists.newArrayList(roots)); } public void traverseRoots(List<Node> roots) { if (roots.isEmpty()) { return; } try { Node scopeRoot = roots.get(0).getParent(); Preconditions.checkState(scopeRoot != null); sourceName = ""; curNode = scopeRoot; pushScope(scopeRoot); for (Node root : roots) { Preconditions.checkState(root.getParent() == scopeRoot); traverseBranch(root, scopeRoot); } popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException); } } private static final String MISSING_SOURCE = "[source unknown]"; private String formatNode

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>Position(Node n) { if (n == null) { return MISSING_SOURCE + "\n"; } int lineNumber = n.getLineno(); int columnNumber = n.getCharno(); String src = compiler.getSourceLine(sourceName, lineNumber); if (src == null) { src = MISSING_SOURCE; } return sourceName + ":" + lineNumber + ":" + columnNumber + "\n" + src + "\n"; } /** * Traverses a parse tree recursively with a scope, starting with the given * root. This should only be used in the global scope. Otherwise, use * {@link #traverseAtScope}. */ void traverseWithScope(Node root, Scope s) { Preconditions.checkState(s.isGlobal()); sourceName = ""; curNode = root; pushScope(s); traverseBranch(root, null); popScope(); } /** * Traverses a parse tree recursively with a scope, starting at that scope's * root. */ void traverseAtScope(Scope s) { Node n = s.getRootNode(); if (n.getType() == Token.FUNCTION) { // We need to do some extra magic to make sure that the scope doesn't // get re-created when we dive into the function. sourceName = getSourceName(n); curNode = n; pushScope(s); Node args = n.getFirstChild().getNext(); Node body = args.getNext(); traverseBranch(args, n); traverseBranch(body, n); popScope(); } else { traverseWithScope(n, s); } } /** * Traverses an inner node recursively with a refined scope. An inner node may * be any node with a non {@code null} parent (i.e. all nodes except the * root). * * @param node the node to traverse * @param parent the node's parent, it may be not be {@code null} * @param refinedScope the refined scope of the scope currently at the top of * the scope stack or in trivial cases that very scope or {@code null} */ protected void traverseInnerNode(Node node, Node parent, Scope refinedScope) { Preconditions.checkNotNull(parent

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>Name = getSourceName(n); } curNode = n; if (!callback.shouldTraverse(this, n, parent)) return; switch (type) { case Token.CATCH: Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getFirstChild().getType() == Token.NAME); // the first child is the catch var and the third child // is the code block traverseBranch(n.getFirstChild(), n); traverseBranch(n.getFirstChild().getNext().getNext(), n); break; case Token.FUNCTION: traverseFunction(n, parent); break; default: for (Node child = n.getFirstChild(); child != null; ) { // child could be replaced, in which case our child node // would no longer point to the true next Node next = child.getNext(); traverseBranch(child, n); child = next; } break; } curNode = n; callback.visit(this, n, parent); } /** * Traverses a function. */ private void traverseFunction(Node n, Node parent) { Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getType() == Token.FUNCTION); final Node fnName = n.getFirstChild(); boolean anonymous = parent != null && NodeUtil.isFunctionAnonymous(n); if (!anonymous) { // Named functions are parent of the containing scope. traverseBranch(fnName, n); } curNode = n; pushScope(n); if (anonymous) { // Anonymous function names are parent of the contained scope. traverseBranch(fnName, n); } final Node args = fnName.getNext(); final Node body = args.getNext(); // Args traverseBranch(args, n); // Body Preconditions.checkState(body.getNext() == null && body.getType() == Token.BLOCK); traverseBranch(body, n); popScope(); } /** Examines the functions stack for the last instance of a function node. */ @SuppressWarnings("unchecked") public Node getEnclosingFunction() { if (scopes.size() + scopeRoots.size() < 2) { return null; } else { if

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> (scopeRoots.isEmpty()) { return scopes.peek().getRootNode(); } else { return scopeRoots.peek(); } } } /** Creates a new scope (e.g. when entering a function). */ private void pushScope(Node node) { Preconditions.checkState(curNode != null); scopeRoots.push(node); cfgs.push(null); if (scopeCallback != null) { scopeCallback.enterScope(this); } } /** Creates a new scope (e.g. when entering a function). */ private void pushScope(Scope s) { Preconditions.checkState(curNode != null); scopes.push(s); cfgs.push(null); if (scopeCallback != null) { scopeCallback.enterScope(this); } } /** Pops back to the previous scope (e.g. when leaving a function). */ private void popScope() { if (scopeCallback != null) { scopeCallback.exitScope(this); } if (scopeRoots.isEmpty()) { scopes.pop(); } else { scopeRoots.pop(); } cfgs.pop(); } /** Gets the current scope. */ public Scope getScope() { Scope scope = scopes.isEmpty() ? null : scopes.peek(); if (scopeRoots.isEmpty()) { return scope; } Iterator<Node> it = scopeRoots.descendingIterator(); while (it.hasNext()) { scope = scopeCreator.createScope(it.next(), scope); scopes.push(scope); } scopeRoots.clear(); return scope; } /** Gets the control flow graph for the current JS scope. */ public ControlFlowGraph<Node> getControlFlowGraph() { if (cfgs.peek() == null) { ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false); cfa.process(null, getScopeRoot()); cfgs.pop(); cfgs.push(cfa.getCfg()); } return cfgs.peek(); } /** Returns the current scope's root. */ public Node getScopeRoot() { if (scopeRoots.isEmpty()) { return scopes.peek().getRootNode(); } else { return scopeRoots.peek(); } }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> false; errorFormat = ErrorFormat.SINGLELINE; warningsGuard = null; debugFunctionSideEffectsPath = null; jsOutputFile = ""; nameReferenceReportPath = null; nameReferenceGraphPath = null; } /** * Returns the map of define replacements. */ public Map<String, Node> getDefineReplacements() { Map<String, Node> map = Maps.newHashMap(); for (Map.Entry<String, Object> entry : defineReplacements.entrySet()) { String name = entry.getKey(); Object value = entry.getValue(); if (value instanceof Boolean) { map.put(name, ((Boolean) value).booleanValue() ? new Node(Token.TRUE) : new Node(Token.FALSE)); } else if (value instanceof Integer) { map.put(name, Node.newNumber(((Integer) value).intValue())); } else if (value instanceof Double) { map.put(name, Node.newNumber(((Double) value).doubleValue())); } else { Preconditions.checkState(value instanceof String); map.put(name, Node.newString((String) value)); } } return map; } /** * Sets the value of the {@code @define} variable in JS * to a boolean literal. */ public void setDefineToBooleanLiteral(String defineName, boolean value) { defineReplacements.put(defineName, new Boolean(value)); } /** * Sets the value of the {@code @define} variable in JS to a * String literal. */ public void setDefineToStringLiteral(String defineName, String value) { defineReplacements.put(defineName, value); } /** * Sets the value of the {@code @define} variable in JS to a * number literal. */ public void setDefineToNumberLiteral(String defineName, int value) { defineReplacements.put(defineName, new Integer(value)); } /** * Sets the value of the {@code @define} variable in JS to a * number literal. */ public void setDefineToDoubleLiteral(String defineName, double value) { defineReplacements.put(defineName, new Double(value)); } /** * Skip all possible passes, to make the compiler as fast as

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>getNext(); if (key.getJSDocInfo() != null && key.getNext().getType() == Token.FUNCTION) { value.setJSDocInfo(key.getJSDocInfo()); } } } for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { normalizeJsDocAnnotations(child); } } /** * Covert EXPR_VOID to EXPR_RESULT to simplify the rest of the code. */ private void normalizeNodeTypes(Node n) { if (n.getType() == Token.EXPR_VOID) { n.setType(Token.EXPR_RESULT); reportChange(); } // Remove unused properties to minimize differences between ASTs // produced by the two parsers. if (n.getType() == Token.FUNCTION) { n.removeProp(Node.FUNCTION_PROP); reportChange(); } normalizeBlocks(n); for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { // This pass is run during the CompilerTestCase validation, so this // parent pointer check serves as a more general check. Preconditions.checkState(child.getParent() == n); normalizeNodeTypes(child); } } /** * Add blocks to IF, WHILE, DO, etc. */ private void normalizeBlocks(Node n) { if (NodeUtil.isControlStructure(n) && n.getType() != Token.LABEL && n.getType() != Token.SWITCH) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (NodeUtil.isControlStructureCodeBlock(n,c) && c.getType() != Token.BLOCK) { Node newBlock = new Node(Token.BLOCK); n.replaceChild(c, newBlock); if (c.getType() != Token.EMPTY) { newBlock.addChildrenToFront(c); } else { newBlock.setWasEmptyNode(true); } c = newBlock; reportChange(); } } } } }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>ERROR = DiagnosticType.warning( "JSC_NAME_REFERENCE_IN_EXTERNS", "accessing name {0} in externs has no effect"); static final DiagnosticType INVALID_FUNCTION_DECL = DiagnosticType.error("JSC_INVALID_FUNCTION_DECL", "Syntax error: function declaration must have a name"); private CompilerInput synthesizedExternsInput = null; private Node synthesizedExternsRoot = null; private final AbstractCompiler compiler; // Whether this is the post-processing sanity check. private final boolean sanityCheck; VarCheck(AbstractCompiler compiler) { this(compiler, false); } VarCheck(AbstractCompiler compiler, boolean sanityCheck) { this.compiler = compiler; this.sanityCheck = sanityCheck; } /** {@inheritDoc} */ public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, externs, new NameRefInExternsCheck()); NodeTraversal.traverseRoots( compiler, Lists.newArrayList(externs, root), this); } /** {@inheritDoc} */ public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() != Token.NAME) { return; } if (NodeUtil.isLabelName(n)) { return; } String varName = n.getString(); // Only a function can have an empty name. if (varName.isEmpty()) { Preconditions.checkState(NodeUtil.isFunction(parent)); // A function declaration with an empty name passes Rhino, // but is supposed to be a syntax error according to the spec. if (!NodeUtil.isAnonymousFunction(parent)) { t.report(n, INVALID_FUNCTION_DECL); } return; } // Check that the var has been declared. Scope scope = t.getScope(); Scope.Var var = scope.getVar(varName); if (var == null) { if (NodeUtil.isAnonymousFunction(parent)) { // e.g. [ function foo() {} ], it's okay if "foo" isn't defined in the // current scope. } else { t.report(n, UNDEFINED_VAR_ERROR, varName); if (sanityCheck) { throw new IllegalStateException("Unexpected

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>(CompilerInput input) { inputs.add(input); input.setModule(this); } /** Adds a source code input to this module. */ public void addFirst(CompilerInput input) { inputs.add(0, input); input.setModule(this); } /** Adds a source code input to this module directly after other. */ public void addAfter(CompilerInput input, CompilerInput other) { Preconditions.checkState(inputs.contains(other)); inputs.add(inputs.indexOf(other), input); input.setModule(this); } /** Adds a dependency on another module. */ public void addDependency(JSModule dep) { Preconditions.checkState(dep != this); deps.add(dep); } /** Removes all of the inputs from this module. */ public void removeAll() { for (CompilerInput input : inputs) { input.setModule(null); } inputs.clear(); } /** * Gets the list of modules that this module depends on. * * @return A list that may be empty but not null */ public List<JSModule> getDependencies() { return deps; } /** * Returns the transitive closure of dependencies starting from the * dependencies of this module. */ public Set<JSModule> getAllDependencies() { Set<JSModule> allDeps = Sets.newHashSet(deps); List<JSModule> workList = Lists.newArrayList(deps); while (workList.size() > 0) { JSModule module = workList.remove(workList.size() - 1); for (JSModule dep : module.getDependencies()) { if (allDeps.add(dep)) { workList.add(dep); } } } return allDeps; } /** Returns this module and all of its dependencies in one list. */ public Set<JSModule> getThisAndAllDependencies() { Set<JSModule> deps = getAllDependencies(); deps.add(this); return deps; } /** * Gets this module's list of source code inputs. * * @return A list that may be empty but not null */ public List<CompilerInput> getInputs() { return inputs; } /** Returns the input with the

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> import com.google.javascript.rhino.jstype.ObjectType; import com.google.javascript.rhino.jstype.StaticSlot; import com.google.javascript.rhino.jstype.UnionType; import com.google.javascript.rhino.jstype.Visitor; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; /** * Chainable reverse abstract interpreter providing basic functionality. * * */ abstract class ChainableReverseAbstractInterpreter implements ReverseAbstractInterpreter { protected final CodingConvention convention; final JSTypeRegistry typeRegistry; private ChainableReverseAbstractInterpreter firstLink; private ChainableReverseAbstractInterpreter nextLink; /** * Constructs an interpreter, which is the only link in a chain. Interpreters * can be appended using {@link #append}. */ ChainableReverseAbstractInterpreter(CodingConvention convention, JSTypeRegistry typeRegistry) { Preconditions.checkNotNull(convention); this.convention = convention; this.typeRegistry = typeRegistry; firstLink = this; nextLink = null; } /** * Appends a link to {@code this}, returning the updated last link. * <p> * The pattern {@code new X().append(new Y())...append(new Z())} forms a * chain starting with X, then Y, then ... Z. * @param lastLink a chainable interpreter, with no next link * @return the updated last link */ ChainableReverseAbstractInterpreter append( ChainableReverseAbstractInterpreter lastLink) { Preconditions.checkArgument(lastLink.nextLink == null); this.nextLink = lastLink; lastLink.firstLink = this.firstLink; return lastLink; } /** * Gets the first link of this chain. */ ChainableReverseAbstractInterpreter getFirst() { return firstLink; } /** * Calculates the preciser scope starting with the first link. */ protected FlowScope firstPreciserScopeKnowingConditionOutcome(Node condition, FlowScope blindScope, boolean outcome) { return firstLink.getPreciserScopeKnowingConditionOutcome( condition, blindScope, outcome); } /** * Delegates the calculation of the preciser scope to the next link. *

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> If there is no next link, returns the blind scope. */ protected FlowScope nextPreciserScopeKnowingConditionOutcome(Node condition, FlowScope blindScope, boolean outcome) { return nextLink != null ? nextLink.getPreciserScopeKnowingConditionOutcome( condition, blindScope, outcome) : blindScope; } /** * Returns the type of a node in the given scope if the node corresponds to a * name whose type is capable of being refined. * @return The current type of the node if it can be refined, null otherwise. */ JSType getTypeIfRefinable(Node node, FlowScope scope) { switch (node.getType()) { case Token.NAME: StaticSlot<JSType> nameVar = scope.getSlot(node.getString()); if (nameVar != null) { JSType nameVarType = nameVar.getType(); if (nameVarType == null) { nameVarType = node.getJSType(); } return nameVarType; } return null; case Token.GETPROP: String qualifiedName = node.getQualifiedName(); if (qualifiedName == null) { return null; } StaticSlot<JSType> propVar = scope.getSlot(qualifiedName); JSType propVarType = null; if (propVar != null) { propVarType = propVar.getType(); } if (propVarType == null) { propVarType = node.getJSType(); } if (propVarType == null) { propVarType = getNativeType(UNKNOWN_TYPE); } return propVarType; } return null; } /** * Declares a refined type in {@code scope} for the name represented by * {@code node}. It must be possible to refine the type of the given node in * the given scope, as determined by {@link #getTypeIfRefinable}. */ protected void declareNameInScope(FlowScope scope, Node node, JSType type) { switch (node.getType()) { case Token.NAME: scope.inferSlotType(node.getString(), type); break; case Token.GETPROP: String qualifiedName = node.getQualifiedName(); Preconditions.checkNotNull(qualifiedName); JS

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> ReverseAbstractInterpreter reverseInterpreter, JSTypeRegistry typeRegistry) { this(compiler, reverseInterpreter, typeRegistry, null, null, CheckLevel.WARNING, CheckLevel.OFF); } /** Turn on the missing property check. Returns this for easy chaining. */ TypeCheck reportMissingProperties(boolean report) { reportMissingProperties = report; return this; } /** * Main entry point for this phase of processing. This follows the pattern for * JSCompiler phases. * * @param externsRoot The root of the externs parse tree. * @param jsRoot The root of the input parse tree to be checked. */ public void process(Node externsRoot, Node jsRoot) { Preconditions.checkNotNull(scopeCreator); Preconditions.checkNotNull(topScope); Node externsAndJs = jsRoot.getParent(); Preconditions.checkState(externsAndJs != null); Preconditions.checkState( externsRoot == null || externsAndJs.hasChild(externsRoot)); if (externsRoot != null) { check(externsRoot, true); } check(jsRoot, false); potentialChecks.flush(); } /** Main entry point of this phase for testing code. */ public Scope processForTesting(Node externsRoot, Node jsRoot) { Preconditions.checkState(scopeCreator == null); Preconditions.checkState(topScope == null); Preconditions.checkState(jsRoot.getParent() != null); Node externsAndJsRoot = jsRoot.getParent(); scopeCreator = new MemoizedScopeCreator(new TypedScopeCreator(compiler)); topScope = scopeCreator.createScope(externsAndJsRoot, null); TypeInferencePass inference = new TypeInferencePass(compiler, reverseInterpreter, topScope, scopeCreator); inference.process(externsRoot, jsRoot); process(externsRoot, jsRoot); return topScope; } public void check(Node node, boolean externs) { Preconditions.checkNotNull(node); NodeTraversal t = new NodeTraversal(compiler, this, scopeCreator); inExterns = externs; t.traverseWithScope(node, topScope); if (externs) { inferJSDocInfo.process(node, null); } else { inferJSDocInfo.

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>; } } // TODO(nicksantos): TypeCheck should never be attaching types to nodes. // All types should be attached by TypeInference. This is not true today // for legacy reasons. There are a number of places where TypeInference // doesn't attach a type, as a signal to TypeCheck that it needs to check // that node's type. /** * Ensure that the given node has a type. If it does not have one, * attach the UNKNOWN_TYPE. */ private void ensureTyped(NodeTraversal t, Node n) { ensureTyped(t, n, getNativeType(UNKNOWN_TYPE)); } private void ensureTyped(NodeTraversal t, Node n, JSTypeNative type) { ensureTyped(t, n, getNativeType(type)); } /** * Enforces type casts, and ensures the node is typed. * * A cast in the way that we use it in JSDoc annotations never * alters the generated code and therefore never can induce any runtime * operation. What this means is that a 'cast' is really just a compile * time constraint on the underlying value. In the future, we may add * support for run-time casts for compiled tests. * * To ensure some shred of sanity, we enforce the notion that the * type you are casting to may only meaningfully be a narrower type * than the underlying declared type. We also invalidate optimizations * on bad type casts. * * @param t The traversal object needed to report errors. * @param n The node getting a type assigned to it. * @param type The type to be assigned. */ private void ensureTyped(NodeTraversal t, Node n, JSType type) { // Make sure FUNCTION nodes always get function type. Preconditions.checkState(n.getType() != Token.FUNCTION || type instanceof FunctionType || type.isUnknownType()); JSDocInfo info = n.getJSDocInfo(); if (info != null) { if (info.hasType()) { JSType infoType = info.getType().evaluate(t.getScope()); validator.expectCanCast(t, n, infoType, type); type = infoType; } if (info.isImplicitCast() && !

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> CompilerPass create(AbstractCompiler compiler) { Preconditions.checkState(!isCreated || !isOneTimePass, "One-time passes cannot be run multiple times: " + name); isCreated = true; return createInternal(compiler); } /** * Creates a new compiler pass to be run. */ abstract protected CompilerPass createInternal(AbstractCompiler compiler); }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>; private final ScopeCreator scopeCreator; // Mutex so that the symbol table may only be acquired by one pass // at a time. private boolean locked = false; // Memoized data with the pass that has currently acquired the // symbol table. private MemoizedData cache = null; SymbolTable(AbstractCompiler compiler) { this.compiler = compiler; compiler.addChangeHandler(this); scopeCreator = new SyntacticScopeCreator(compiler); } synchronized void acquire() { Preconditions.checkState(!locked, "SymbolTable already acquired"); locked = true; } synchronized void release() { Preconditions.checkState(locked, "SymbolTable already released"); locked = false; } /** * Returns the scope at the given node. */ @Override public Scope createScope(Node n, Scope parent) { Preconditions.checkArgument( n.getType() == Token.BLOCK || n.getType() == Token.FUNCTION); ensureCacheInitialized(); if (!cache.scopes.containsKey(n)) { cache.scopes.put(n, scopeCreator.createScope(n, parent)); } return cache.scopes.get(n); } /** * Ensure that the memoization data structures have been initialized. */ private void ensureCacheInitialized() { Preconditions.checkState(locked, "Unacquired symbol table"); if (cache == null) { cache = new MemoizedData(); } } /** * If the AST changes, and the symbol table has not been acquired, then * all of our memoized data structures become stale. So delete them. */ @Override public void reportChange() { if (!locked) { cache = null; } } /** * All the data structures cached by this table. */ private static class MemoizedData { private Map<Node, Scope> scopes = Maps.newHashMap(); } //---------------------------------------------------------------------------- // Verification of consistency. Only for tests. /** * Check that this symbol table has been kept up to date. Compiler warnings * will be emitted if anything is wrong. * @param expectedRoot The root of the expected AST. * @param actualRoot The root of the actual AST used with this symbol table. */ void verify(Node expectedRoot, Node actualRoot) {

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> VerifyingCallback callback = new VerifyingCallback( expectedRoot, actualRoot); callback.verify(); } /** * A callback that traverses an AST root and builds all the * secondary data structures for it. */ private class VerifyingCallback implements ScopedCallback { private final List<Scope> expectedScopes = Lists.newArrayList(); private final List<Scope> actualScopes = Lists.newArrayList(); private boolean collectingExpected = true; private final Node actualRoot; private final Node expectedRoot; private VerifyingCallback(Node expectedRoot, Node actualRoot) { this.actualRoot = actualRoot; this.expectedRoot = expectedRoot; } @Override public boolean shouldTraverse( NodeTraversal nodeTraversal, Node n, Node parent) { return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) {} @Override public void enterScope(NodeTraversal t) {} @Override public void exitScope(NodeTraversal t) { if (collectingExpected) { expectedScopes.add(t.getScope()); } else { actualScopes.add(t.getScope()); } } private void verify() { if (cache == null) { // The symbol table was never used, so no need to check anything. return; } if (!cache.scopes.isEmpty()) { verifyScopes(); } } private void verifyScopes() { collectingExpected = true; NodeTraversal.traverse(compiler, expectedRoot, this); collectingExpected = false; (new NodeTraversal(compiler, this, SymbolTable.this)) .traverse(actualRoot); // This must be true unless something went horribly, horribly wrong. Preconditions.checkState(expectedScopes.size() == actualScopes.size()); for (int i = 0; i < expectedScopes.size(); i++) { Scope expectedScope = expectedScopes.get(i); Scope actualScope = actualScopes.get(i); if (expectedScope.getVarCount() != actualScope.getVarCount()) { compiler.report( JSError.make( VARIABLE_COUNT_MISMATCH, Integer.toString(expectedScope.getVarCount()), Integer.toString(actualScope.getVarCount()))); } else { Iterator<Var> it =

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> want the new node to get its parent's line number. int lineno = node.getLineno(); irNode.setLineno(lineno); int charno = position2charno(node.getAbsolutePosition()); irNode.setCharno(charno); } } if (node.getJsDoc() != null) { irNode.putProp(TMP_JSDOC_PROP, node.getJsDoc()); } return irNode; } /** * Parses all temporary JsDoc strings in this node and all its children * recursively as well. Assumes the remaining JsDoc strings are contained in * pre-order with skips allowed, in the given comments, after the given index. * * @param node The current node to start parsing at. * @param comments An array of all comments in the source. * @param ci Current index into the array of comments. * * @return Current index into the array of comments after parsing this node. */ private int parseAllJsDocInfo(Node node, Comment[] comments, int ci) { if (ci >= comments.length) { // There are no comments left. return ci; } // Parse the JsDoc string on the current node, if any. if (node.getProp(TMP_JSDOC_PROP) != null) { String jsDoc = (String) node.getProp(TMP_JSDOC_PROP); // Find the match of the JsDoc string in the array of comments. while (comments[ci].getCommentType() != JSDOC || !comments[ci].getValue().equals(jsDoc)) { ci++; Preconditions.checkState(ci < comments.length); } JSDocInfo info = parseJSDocInfo(jsDoc, comments[ci].getLineno(), comments[ci].getAbsolutePosition()); node.setJSDocInfo(info); if (info != null && info.hasEnumParameterType()) { if (node.getType() == Token.NAME) { registry.identifyEnumName(node.getString()); } else if (node.getType() == Token.VAR && node.getChildCount() == 1) { registry.identifyEnumName(node.getFirstChild().getString()); } else if (node.getType() == Token.ASSIGN)

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> that reports errors and warnings to an output * stream. */ public Compiler(PrintStream stream) { this(); setErrorManager( new PrintStreamErrorManager(createMessageFormatter(), stream)); } /** * Creates a Compiler that uses a custom error manager. */ public Compiler(ErrorManager errorManager) { this(); setErrorManager(errorManager); } CompilerOptions createDefaultOptions() { return new CompilerOptions(); } /** * Acquires the symbol table. */ @Override SymbolTable acquireSymbolTable() { if (symbolTable == null) { symbolTable = new SymbolTable(this); } symbolTable.acquire(); return symbolTable; } /** * Sets the error manager. * * @param errorManager the error manager, it cannot be {@code null} */ public void setErrorManager(ErrorManager errorManager) { Preconditions.checkNotNull( errorManager, "the error manager cannot be null"); this.errorManager = errorManager; } /** * Creates a message formatter instance corresponding to the value of * {@link CompilerOptions}. */ private MessageFormatter createMessageFormatter() { boolean colorize = options_.shouldColorizeErrorOutput(); return options_.errorFormat.toFormatter(this, colorize); } /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSSourceFile[] inputs, CompilerOptions options) { externs_ = makeCompilerInput(externs, true); modules_ = null; moduleGraph_ = null; inputs_ = makeCompilerInput(inputs, false); options_ = options; initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { checkFirstModule(modules); externs_ = makeCompilerInput(externs, true); modules_ = modules; // Generate the module graph, and report any errors in

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>( JSSourceFile extern, JSSourceFile input, CompilerOptions options) { return compile(extern, new JSSourceFile[] { input }, options); } public Result compile( JSSourceFile extern, JSSourceFile[] input, CompilerOptions options) { return compile(new JSSourceFile[] { extern }, input, options); } public Result compile( JSSourceFile extern, JSModule[] modules, CompilerOptions options) { return compile(new JSSourceFile[] { extern }, modules, options); } /** * Compiles a list of inputs. */ public Result compile(JSSourceFile[] externs, JSSourceFile[] inputs, CompilerOptions options) { // The compile method should only be called once. Preconditions.checkState(jsRoot == null); try { init(externs, inputs, options); if (hasErrors()) { return getResult(); } return compile(); } finally { Tracer t = newTracer("generateReport"); errorManager.generateReport(); stopTracer(t, "generateReport"); } } /** * Compiles a list of modules. */ public Result compile(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { // The compile method should only be called once. Preconditions.checkState(jsRoot == null); try { init(externs, modules, options); if (hasErrors()) { return getResult(); } return compile(); } finally { Tracer t = newTracer("generateReport"); errorManager.generateReport(); stopTracer(t, "generateReport"); } } private Result compile() { return runInCompilerThread(new Callable<Result>() { public Result call() throws Exception { compileInternal(); return getResult(); } }); } /** * Disable threads. This is for clients that run on AppEngine and * don't have threads. */ public void disableThreads() { useThreads = false; } @SuppressWarnings("unchecked") private <T> T runInCompilerThread(final Callable<T> callable) { // Under JRE 1.6, the jscompiler overflows the stack when running on some // large or complex js code.

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> /** * Create the passes object. Clients should use setPassConfig instead of * overriding this. */ PassConfig createPassConfigInternal() { return new DefaultPassConfig(options_); } /** * @param passes The PassConfig to use with this Compiler. * @throws NullPointerException if passes is null * @throws IllegalStateException if this.passes has already been assigned */ public void setPassConfig(PassConfig passes) { // Important to check for null because if setPassConfig(null) is // called before this.passes is set, getPassConfig() will create a // new PassConfig object and use that, which is probably not what // the client wanted since he or she probably meant to use their // own PassConfig object. Preconditions.checkNotNull(passes); if (this.passes != null) { throw new IllegalStateException("this.passes has already been assigned"); } this.passes = passes; } /** * Carry out any special checks or procedures that need to be done before * proceeding with rest of the compilation process. * * @return true, to continue with compilation */ boolean precheck() { return true; } public void check() { runCustomPasses(CustomPassExecutionTime.BEFORE_CHECKS); PhaseOptimizer phaseOptimizer = new PhaseOptimizer(this, tracker); if (options_.devMode == DevMode.EVERY_PASS) { phaseOptimizer.setSanityCheck(sanityCheck); } phaseOptimizer.consume(getPassConfig().getChecks()); phaseOptimizer.process(externsRoot, jsRoot); if (hasErrors()) { return; } if (options_.instrumentationTemplate != null || options_.recordFunctionInformation) { computeFunctionNames(); } if (options_.removeTryCatchFinally) { removeTryCatchFinally(); } if (!options_.stripTypes.isEmpty() || !options_.stripNameSuffixes.isEmpty() || !options_.stripTypePrefixes.isEmpty() || !options_.stripNamePrefixes.isEmpty()) { stripCode(options_.stripTypes, options_.stripNameSuffixes, options_.stripTypePrefixes, options_.stripNamePrefixes); } runCustomPasses(CustomPassExecutionTime.BEFORE_OPTIMIZATIONS); // Ideally, this pass should be the first pass

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> boolean outputStringUsage) { logger_.info("Aliasing strings"); startPass("aliasStrings"); AliasStrings aliasStrings = new AliasStrings( this, getModuleGraph(), aliasAllStrings ? null : aliasableStrings, aliasStringsBlacklist, outputStringUsage); process(aliasStrings); endPass(); } private void aliasKeywords() { logger_.info("Aliasing true/false/null"); startPass("aliasKeywords"); AliasKeywords aliasKeywords = new AliasKeywords(this); process(aliasKeywords); endPass(); } /** * Runs custom passes that are designated to run at a particular time. */ private void runCustomPasses(CustomPassExecutionTime executionTime) { if (options_.customPasses != null) { Tracer t = newTracer("runCustomPasses"); try { for (CompilerPass p : options_.customPasses.get(executionTime)) { process(p); } } finally { stopTracer(t, "runCustomPasses"); } } } private Tracer currentTracer = null; private String currentPassName = null; /** * Marks the beginning of a pass. */ void startPass(String passName) { Preconditions.checkState(currentTracer == null); currentPassName = passName; currentTracer = newTracer(passName); } /** * Marks the end of a pass. */ void endPass() { Preconditions.checkState(currentTracer != null, "Tracer should not be null at the end of a pass."); stopTracer(currentTracer, currentPassName); String passToCheck = currentPassName; currentPassName = null; currentTracer = null; maybeSanityCheck(passToCheck); } /** * Returns a new tracer for the given pass name. */ Tracer newTracer(String passName) { String comment = passName + (recentChange.hasCodeChanged() ? " on recently changed AST" : ""); if (options_.tracer.isOn()) { tracker.recordPassStart(passName); } return new Tracer("Compiler", comment); } void stopTracer(Tracer t, String passName) { long result = t.stop(); if (options_.tracer.is

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> inputsByName_.get(name); } @Override public CompilerInput newExternInput(String name) { if (inputsByName_.containsKey(name)) { throw new IllegalArgumentException("Conflicting externs name: " + name); } SourceAst ast = new SyntheticAst(name); CompilerInput input = new CompilerInput(ast, name, true); inputsByName_.put(name, input); externsRoot.addChildToFront(ast.getAstRoot(this)); return input; } /** Add a source input dynamically. Intended for incremental compilation. */ void addIncrementalSourceAst(JsAst ast) { String sourceName = ast.getSourceFile().getName(); Preconditions.checkState( getInput(sourceName) == null, "Duplicate input of name " + sourceName); inputsByName_.put(sourceName, new CompilerInput(ast)); } @Override JSModuleGraph getModuleGraph() { return moduleGraph_; } @Override public JSTypeRegistry getTypeRegistry() { if (typeRegistry == null) { typeRegistry = new JSTypeRegistry(oldErrorReporter); } return typeRegistry; } @Override ScopeCreator getScopeCreator() { return getPassConfig().getScopeCreator(); } @Override public Scope getTopScope() { return getPassConfig().getTopScope(); } @Override public ReverseAbstractInterpreter getReverseAbstractInterpreter() { if (abstractInterpreter == null) { ChainableReverseAbstractInterpreter interpreter = new SemanticReverseAbstractInterpreter( getCodingConvention(), getTypeRegistry()); if (options_.closurePass) { interpreter = new ClosureReverseAbstractInterpreter( getCodingConvention(), getTypeRegistry()) .append(interpreter).getFirst(); } abstractInterpreter = interpreter; } return abstractInterpreter; } @Override TypeValidator getTypeValidator() { return typeValidator; } //------------------------------------------------------------------------ // Parsing //------------------------------------------------------------------------ /** * Parses the externs and main inputs. * * @return A synthetic root node whose two children are the externs root * and the main root */ Node parseInputs() { boolean devMode = options_.devMode != DevMode.OFF; // If old roots exist (we are parsing a second time), detach each of the // individual file parse trees.

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> to dot syntax"); startPass("convertToDottedProperties"); process(new ConvertToDottedProperties(this)); endPass(); } void instrumentFunctions() { logger_.info("Instrumenting functions"); startPass("instrumentFunctions"); try { FileReader templateFile = new FileReader(options_.instrumentationTemplate); process(new InstrumentFunctions(this, functionNames_, options_.instrumentationTemplate, options_.appNameStr, templateFile)); } catch (IOException e) { report(JSError.make(READ_ERROR, options_.instrumentationTemplate)); } endPass(); } void recordFunctionInformation() { logger_.info("Recording function information"); startPass("recordFunctionInformation"); RecordFunctionInformation recordFunctionInfoPass = new RecordFunctionInformation(this, functionNames_); process(recordFunctionInfoPass); functionInformationMap_ = recordFunctionInfoPass.getMap(); endPass(); } protected final CodeChangeHandler.RecentChange recentChange = new CodeChangeHandler.RecentChange(); private final List<CodeChangeHandler> codeChangeHandlers = Lists.<CodeChangeHandler>newArrayList(); @Override void addChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.add(handler); } @Override void removeChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.remove(handler); } /** * All passes should call reportCodeChange() when they alter * the JS tree structure. This is verified by CompilerTestCase. * This allows us to optimize to a fixed point. */ @Override public void reportCodeChange() { for (CodeChangeHandler handler : codeChangeHandlers) { handler.reportChange(); } } @Override public CodingConvention getCodingConvention() { return codingConvention; } public void setCodingConvention(CodingConvention convention) { Preconditions.checkState(convention != null); codingConvention = convention; } @Override public boolean isIdeMode() { return options_.ideMode; } @Override public boolean isTypeCheckingEnabled() { return options_.checkTypes; } //------------------------------------------------------------------------ // Error reporting //------------------------------------------------------------------------ @Override void report(JSError error) { CheckLevel level = error.level; WarningsGuard guard = options_.getWarningsGuard(); if (guard !=

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.javascript.jscomp.parsing.ParserRunner; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.io.IOException; import java.util.logging.Logger; /** * Generates an AST for a JavaScript source file. * * */ public class JsAst implements SourceAst { private static final Logger logger_ = Logger.getLogger(JsAst.class.getName()); private static final long serialVersionUID = 1L; private transient SourceFile sourceFile; private String fileName; private Node root; public JsAst(SourceFile sourceFile) { this.sourceFile = sourceFile; this.fileName = sourceFile.getName(); } @Override public Node getAstRoot(AbstractCompiler compiler) { if (root == null) { createAst(compiler); } return root; } @Override public void clearAst() { root = null; // While we're at it, clear out any saved text in the source file on // the assumption that if we're dumping the parse tree, then we probably // assume regenerating everything else is a smart idea also. sourceFile.clearCachedSource(); } @Override public SourceFile getSourceFile() { return sourceFile; } @Override public void setSourceFile(SourceFile file) { Preconditions.checkState(fileName.equals(file.getName())); sourceFile = file; } private void createAst(AbstractCompiler compiler) { try { parse

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> Create a named type based on the reference. */ public NamedType(JSTypeRegistry registry, String reference, String sourceName, int lineno, int charno) { super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); Preconditions.checkNotNull(reference); this.reference = reference; this.sourceName = sourceName; this.lineno = lineno; this.charno = charno; } @Override public void forgiveUnknownNames() { forgiving = true; } /** Whether the type name has been resolved to an enum or object. */ public boolean isResolved() { return isResolved; } /** Clears the resolved field. */ public void clearResolved() { isResolved = false; } /** Returns the type to which this refers (which is unknown if unresolved). */ public JSType getReferencedType() { return referencedType; } @Override public String getName() { return reference; } @Override public String toString() { return reference; } @Override public boolean hasName() { return true; } @Override public boolean isNamedType() { return true; } @Override boolean isNominalType() { return true; } /** * Two named types are equal if they are the same {@code ObjectType} object. * This is complicated by the fact that equals is sometimes called before we * have a chance to resolve the type names. * * @return {@code true} iff {@code that} == {@code this} or {@code that} * is a {@link NamedType} whose reference is the same as ours, * or {@code that} is the type we reference. */ @Override public boolean equals(Object that) { if (this == that) { return true; } else if (that instanceof ObjectType) { ObjectType objType = (ObjectType) that; return objType.isNominalType() && reference.equals(objType.getName()); } return false; } @Override public int hashCode() { return reference.hashCode(); } /** * Resolve the referenced type within the enclosing scope. */ public void resolve(ErrorReporter t, StaticScope<JSType> enclosing) {

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>); sourceName = null; Scope returnedScope = scope; scope = null; return returnedScope; } private void scanRoot(Node n, Scope parent) { if (n.getType() == Token.FUNCTION) { sourceName = (String) n.getProp(Node.SOURCENAME_PROP); final Node fnNameNode = n.getFirstChild(); final Node args = fnNameNode.getNext(); final Node body = args.getNext(); // Bleed the function name into the scope, if it hasn't // been declared in the outer scope. String fnName = fnNameNode.getString(); if (!fnName.isEmpty() && NodeUtil.isFunctionAnonymous(n)) { declareVar(fnName, fnNameNode, n, null, null, n); } // Args: Declare function variables Preconditions.checkState(args.getType() == Token.LP); for (Node a = args.getFirstChild(); a != null; a = a.getNext()) { Preconditions.checkState(a.getType() == Token.NAME); declareVar(a.getString(), a, args, n, null, n); } // Body scanVars(body, n); } else { // It's the global block Preconditions.checkState(scope.getParent() == null); scanVars(n, null); } } /** * Scans and gather variables declarations under a Node */ private void scanVars(Node n, Node parent) { switch (n.getType()) { case Token.VAR: // Declare all variables. e.g. var x = 1, y, z; for (Node child = n.getFirstChild(); child != null;) { Node next = child.getNext(); Preconditions.checkState(child.getType() == Token.NAME); String name = child.getString(); declareVar(name, child, n, parent, null, n); child = next; } return; case Token.FUNCTION: if (NodeUtil.isFunctionAnonymous(n)) { return; } String fnName = n.getFirstChild().getString(); if (fnName.isEmpty()) { // This is invalid, but allow it so the checks can catch it. return; } declareVar(fnName,

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> n.getFirstChild(), n, parent, null, n); return; // should not examine function's children case Token.CATCH: Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getFirstChild().getType() == Token.NAME); // the first child is the catch var and the third child // is the code block final Node var = n.getFirstChild(); final Node block = var.getNext().getNext(); declareVar(var.getString(), var, n, parent, null, n); scanVars(block, n); return; // only one child to scan case Token.SCRIPT: sourceName = (String) n.getProp(Node.SOURCENAME_PROP); break; } // Variables can only occur in statement-level nodes, so // we only need to traverse children in a couple special cases. if (NodeUtil.isControlStructure(n) || NodeUtil.isStatementBlock(n)) { for (Node child = n.getFirstChild(); child != null;) { Node next = child.getNext(); scanVars(child, n); child = next; } } } /** * Interface for injectable duplicate handling. */ interface RedeclarationHandler { void onRedeclaration( Scope s, String name, Node n, Node parent, Node gramps, Node nodeWithLineNumber); } /** * The default handler for duplicate declarations. */ private class DefaultRedeclarationHandler implements RedeclarationHandler { public void onRedeclaration( Scope s, String name, Node n, Node parent, Node gramps, Node nodeWithLineNumber) { // Don't allow multiple variables to be declared at the top level scope if (!compiler.getCodingConvention().allowsVariableRedeclaration( scope, name, parent)) { Scope.Var origVar = scope.getVar(name); Node origParent = origVar.getParentNode(); if (origParent.getType() == Token.CATCH && parent.getType() == Token.CATCH) { // Okay, both are 'catch(x)' variables. return; } boolean allowDupe = false; JSDocInfo info = n.getJSDocInfo(); if (info == null) { info = parent.getJ

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> if (options.inlineFunctions) { passes.add(inlineFunctions); } if (options.removeUnusedVars) { if (options.deadAssignmentElimination) { passes.add(deadAssignmentsElimination); } passes.add(removeUnusedVars); } assertAllLoopablePasses(passes); return passes; } /** Creates several passes aimed at removing code. */ private List<PassFactory> getCodeRemovingPasses( boolean beforeSmartNameRemoval) { List<PassFactory> passes = Lists.newArrayList(); if (options.inlineVariables && !beforeSmartNameRemoval) { passes.add(inlineVariables); } else if (options.inlineConstantVars) { passes.add(inlineConstants); } if (options.removeConstantExpressions) { passes.add(removeConstantExpressions); } if (options.foldConstants) { // These used to be one pass. passes.add(minimizeExitPoints); passes.add(foldConstants); } if (options.removeDeadCode) { passes.add(removeUnreachableCode); } if (options.removeUnusedPrototypeProperties) { passes.add(removeUnusedPrototypeProperties); } assertAllLoopablePasses(passes); return passes; } /** * Checks for code that is probably wrong (such as stray expressions). */ // TODO(bolinfest): Write a CompilerPass for this. final PassFactory suspiciousCode = new PassFactory("suspiciousCode", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { List<Callback> sharedCallbacks = Lists.newArrayList(); sharedCallbacks.add(new CheckAccidentalSemicolon(CheckLevel.WARNING)); sharedCallbacks.add(new CheckSideEffects(CheckLevel.WARNING)); if (options.checkGlobalThisLevel.isOn()) { sharedCallbacks.add( new CheckGlobalThis(compiler, options.checkGlobalThisLevel)); } return combineChecks(compiler, sharedCallbacks); } }; /** Verify that all the passes are one-time passes. */ private void assertAllOneTimePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(pass.isOneTimePass());

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> } } /** Verify that all the passes are multi-run passes. */ private void assertAllLoopablePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(!pass.isOneTimePass()); } } /** Checks for validity of the control structures. */ private final PassFactory checkControlStructures = new PassFactory("checkControlStructures", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ControlStructureCheck(compiler); } }; /** Checks that all constructed classes are goog.require()d. */ private final PassFactory checkRequires = new PassFactory("checkRequires", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckRequiresForConstructors(compiler, options.checkRequires); } }; /** Makes sure @constructor is paired with goog.provides(). */ private final PassFactory checkProvides = new PassFactory("checkProvides", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckProvides(compiler, options.checkProvides); } }; private static final DiagnosticType GENERATE_EXPORTS_ERROR = DiagnosticType.error( "JSC_GENERATE_EXPORTS_ERROR", "Exports can only be generated if export symbol/property " + "functions are set."); /** Generates exports for @export annotations. */ private final PassFactory generateExports = new PassFactory("generateExports", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { CodingConvention convention = compiler.getCodingConvention(); if (convention.getExportSymbolFunction() != null && convention.getExportPropertyFunction() != null) { return new GenerateExports(compiler, convention.getExportSymbolFunction(), convention.getExportPropertyFunction()); } else { return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR); } } }; /** Generates exports for functions associated with JSUnit. */ private final PassFactory exportTestFunctions = new PassFactory("exportTestFunctions", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { CodingConvention convention = compiler.getCodingConvention(); if (convention.getExportSymbolFunction() != null) {

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> return new ExportTestFunctions(compiler, convention.getExportSymbolFunction()); } else { return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR); } } }; /** Closure pre-processing pass. */ @SuppressWarnings("deprecation") final PassFactory closurePrimitives = new PassFactory("processProvidesAndRequires", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { final ProcessClosurePrimitives pass = new ProcessClosurePrimitives( compiler, options.brokenClosureRequiresLevel, options.rewriteNewDateGoogNow); return new CompilerPass() { @Override public void process(Node externs, Node root) { pass.process(externs, root); setExportedNames(pass.getExportedVariableNames()); } }; } }; /** Checks that CSS class names are wrapped in goog.getCssName */ private final PassFactory closureCheckGetCssName = new PassFactory("checkMissingGetCssName", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { String blacklist = options.checkMissingGetCssNameBlacklist; Preconditions.checkState(blacklist != null && !blacklist.isEmpty(), "Not checking use of goog.getCssName because of empty blacklist."); return new CheckMissingGetCssName( compiler, options.checkMissingGetCssNameLevel, blacklist); } }; /** * Processes goog.getCssName. The cssRenamingMap is used to lookup * replacement values for the classnames. If null, the raw class names are * inlined. */ private final PassFactory closureReplaceGetCssName = new PassFactory("renameCssNames", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node jsRoot) { Map<String, Integer> cssNames = null; if (options.gatherCssNames) { cssNames = Maps.newHashMap(); } (new ReplaceCssNames(compiler, cssNames)).process( externs, jsRoot); setCssNames(cssNames); } }; } }; /** * Creates synthetic blocks to prevent FoldConstants from moving code * past markers in the source. */ private final PassFactory

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> the type registry. */ final PassFactory resolveTypes = new PassFactory("resolveTypes", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new GlobalTypeResolver(compiler); } }; /** Rusn type inference. */ private final PassFactory inferTypes = new PassFactory("inferTypes", false) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(typedScopeCreator); makeTypeInference(compiler).process(externs, root); } }; } }; /** Checks type usage */ private final PassFactory checkTypes = new PassFactory("checkTypes", false) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(typedScopeCreator); TypeCheck check = makeTypeCheck(compiler); check.process(externs, root); compiler.getErrorManager().setTypedPercent(check.getTypedPercent()); } }; } }; /** * Checks possible execution paths of the program for problems: missing return * statements and dead code. */ private final PassFactory checkControlFlow = new PassFactory("checkControlFlow", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { List<Callback> callbacks = Lists.newArrayList(); if (options.checkUnreachableCode.isOn()) { callbacks.add( new CheckUnreachableCode(compiler, options.checkUnreachableCode)); } if (options.checkMissingReturn.isOn() && options.checkTypes) { callbacks.add( new CheckMissingReturn(compiler, options.checkMissingReturn)); } return combineChecks(compiler, callbacks); } }; /** Checks access controls. Depends on type-inference. */ private final PassFactory checkAccessControls = new PassFactory("checkAccessControls", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckAccessControls(compiler); } }; /** Executes the given callbacks

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> with a {@link CombinedCompilerPass}. */ private static CompilerPass combineChecks(AbstractCompiler compiler, List<Callback> callbacks) { Preconditions.checkArgument(callbacks.size() > 0); Callback[] array = callbacks.toArray(new Callback[callbacks.size()]); return new CombinedCompilerPass(compiler, array); } /** A compiler pass that resolves types in the global scope. */ private class GlobalTypeResolver implements CompilerPass { private final AbstractCompiler compiler; GlobalTypeResolver(AbstractCompiler compiler) { this.compiler = compiler; } @Override public void process(Node externs, Node root) { if (topScope == null) { typedScopeCreator = new MemoizedScopeCreator(new TypedScopeCreator(compiler)); topScope = typedScopeCreator.createScope(root.getParent(), null); } else { compiler.getTypeRegistry().resolveTypesInScope(topScope); } } } /** Checks global name usage. */ private final PassFactory checkGlobalNames = new PassFactory("Check names", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node jsRoot) { // Create a global namespace for analysis by check passes. // Note that this class does all heavy computation lazily, // so it's OK to create it here. namespaceForChecks = new GlobalNamespace(compiler, jsRoot); new CheckGlobalNames(compiler, options.checkGlobalNamesLevel) .injectNamespace(namespaceForChecks).process(externs, jsRoot); } }; } }; /** Checks for properties that are not read or written */ private final PassFactory checkSuspiciousProperties = new PassFactory("checkSuspiciousProperties", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new SuspiciousPropertiesCheck( compiler, options.checkUndefinedProperties, options.checkUnusedPropertiesEarly ? CheckLevel.WARNING : CheckLevel.OFF); } }; /** Checks that the code is ES5 or Caja compliant. */ private final PassFactory checkStrictMode = new PassFactory("checkStrictMode", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) {

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>Node(token)); } if (type == null) { type = createJSTypeExpression(newStringNode("number")); } if (!jsdocBuilder.recordEnumParameterType(type)) { parser.addWarning("msg.jsdoc.incompat.type", lineno, charno); } token = eatTokensUntilEOL(token); continue retry; case EXPORT: if (!jsdocBuilder.recordExport()) { parser.addWarning("msg.jsdoc.export", stream.getLineno(), stream.getCharno()); } token = eatTokensUntilEOL(); continue retry; case EXTENDS: case IMPLEMENTS: skipEOLs(); token = next(); lineno = stream.getLineno(); charno = stream.getCharno(); boolean matchingRc = false; if (token == JsDocToken.LC) { token = next(); matchingRc = true; } if (token == JsDocToken.STRING) { Node typeNode = parseAndRecordTypeNameNode( token, lineno, charno, matchingRc); lineno = stream.getLineno(); charno = stream.getCharno(); typeNode = wrapNode(Token.BANG, typeNode); if (typeNode != null && !matchingRc) { typeNode.putBooleanProp(Node.BRACELESS_TYPE, true); } type = createJSTypeExpression(typeNode); if (annotation == Annotation.EXTENDS) { if (!jsdocBuilder.recordBaseType(type)) { parser.addWarning( "msg.jsdoc.incompat.type", lineno, charno); } } else { Preconditions.checkState( annotation == Annotation.IMPLEMENTS); if (!jsdocBuilder.recordImplementedInterface(type)) { parser.addWarning("msg.jsdoc.implements.duplicate", lineno, charno); } } token = next(); if (matchingRc) { if (token != JsDocToken.RC) { parser.addWarning("msg.jsdoc.missing.rc", stream.getLineno(), stream.getCharno()); } } else if (token != JsDocToken.EOL && token != JsDocToken.EOF && token != JsDocToken.EOC) {

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>RecordTypeNode(JsDocToken token, int lineno, int startCharno) { return parseAndRecordTypeNode(token, lineno, startCharno, token == JsDocToken.LC, false); } /** * Looks for a type expression at the current token and if found, * returns it. Note that this method consumes input. * * @param token The current token. * @param lineno The line of the type expression. * @param startCharno The starting character position of the type expression. * @param matchingLC Whether the type expression starts with a "{". * @return The type expression found or null if none. */ private Node parseAndRecordTypeNameNode(JsDocToken token, int lineno, int startCharno, boolean matchingLC) { return parseAndRecordTypeNode(token, lineno, startCharno, matchingLC, true); } /** * Looks for a type expression at the current token and if found, * returns it. Note that this method consumes input. * * Parameter type expressions are special for two reasons: * <ol> * <li>They must begin with '{', to distinguish type names from param names. * <li>They may end in '=', to denote optionality. * </ol> * * @param token The current token. * @return The type expression found or null if none. */ private Node parseAndRecordParamTypeNode(JsDocToken token) { Preconditions.checkArgument(token == JsDocToken.LC); int lineno = stream.getLineno(); int startCharno = stream.getCharno(); Node typeNode = parseParamTypeExpressionAnnotation(token); int endCharno = stream.getCharno(); jsdocBuilder.markTypeNode(typeNode, lineno, startCharno, endCharno, true); return typeNode; } /** * Looks for a parameter type expression at the current token and if found, * returns it. Note that this method consumes input. * * @param token The current token. * @param lineno The line of the type expression. * @param startCharno The starting character position of the type expression. * @param matchingLC Whether the type expression starts with a "{". * @param onlyParseSimple

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>. */ private static String trimEnd(String s) { int trimCount = 0; while (trimCount < s.length()) { char ch = s.charAt(s.length() - trimCount - 1); if (Character.isWhitespace(ch)) { trimCount++; } else { break; } } if (trimCount == 0) { return s; } return s.substring(0, s.length() - trimCount); } // Based on ES4 grammar proposed on July 10, 2008. // http://wiki.ecmascript.org/doku.php?id=spec:spec // Deliberately written to line up with the actual grammar rules, // for maximum flexibility. // TODO(nicksantos): The current implementation tries to maintain backwards // compatibility with previous versions of the spec whenever we can. // We should try to gradually withdraw support for these. /** * TypeExpressionAnnotation := TypeExpression | * '{' TopLevelTypeExpression '}' */ private Node parseTypeExpressionAnnotation(JsDocToken token) { if (token == JsDocToken.LC) { skipEOLs(); Node typeNode = parseTopLevelTypeExpression(next()); if (typeNode != null) { skipEOLs(); if (!match(JsDocToken.RC)) { reportTypeSyntaxWarning("msg.jsdoc.missing.rc"); } else { next(); } } return typeNode; } else { return parseTypeExpression(token); } } /** * ParamTypeExpressionAnnotation := * '{' OptionalParameterType '}' | * '{' TopLevelTypeExpression '}' | * '{' '...' TopLevelTypeExpression '}' * * OptionalParameterType := * TopLevelTypeExpression '=' */ private Node parseParamTypeExpressionAnnotation(JsDocToken token) { Preconditions.checkArgument(token == JsDocToken.LC); skipEOLs(); boolean restArg = false; token = next(); if (token == JsDocToken.ELLIPSIS) { token = next(); restArg = true; } Node typeNode = parseTopLevelTypeExpression(token); if (typeNode != null) { skip

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>UnionTypeWithAlternate(JsDocToken token, Node alternate) { Node union = newNode(Token.PIPE); if (alternate != null) { union.addChildToBack(alternate); } Node expr = null; do { if (expr != null) { skipEOLs(); token = next(); Preconditions.checkState( token == JsDocToken.PIPE || token == JsDocToken.COMMA); boolean isPipe = token == JsDocToken.PIPE; if (isPipe && match(JsDocToken.PIPE)) { // We support double pipes for backwards compatiblity. next(); } skipEOLs(); token = next(); } expr = parseTypeExpression(token); if (expr == null) { return null; } union.addChildToBack(expr); // We support commas for backwards compatiblity. } while (match(JsDocToken.PIPE, JsDocToken.COMMA)); if (alternate == null) { skipEOLs(); if (!match(JsDocToken.RP)) { return reportTypeSyntaxWarning("msg.jsdoc.missing.rp"); } next(); } return union; } /** * ArrayType := '[' ElementTypeList ']' * ElementTypeList := <empty> | TypeExpression | '...' TypeExpression * | TypeExpression ',' ElementTypeList */ private Node parseArrayType(JsDocToken token) { Node array = newNode(Token.LB); Node arg = null; boolean hasVarArgs = false; do { if (arg != null) { next(); skipEOLs(); token = next(); } if (token == JsDocToken.ELLIPSIS) { arg = wrapNode(Token.ELLIPSIS, parseTypeExpression(next())); hasVarArgs = true; } else { arg = parseTypeExpression(token); } if (arg == null) { return null; } array.addChildToBack(arg); if (hasVarArgs) { break; } skipEOLs(); } while (match(JsDocToken.COMMA)); if (!match(JsDocToken.RB)) { return reportTypeSyntaxWarning("msg.jsdoc.missing.rb"); } next(); return array;

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> parent) { switch (n.getType()) { case Token.CALL: String className = findRequire ? codingConvention.extractClassNameIfRequire(n, parent) : codingConvention.extractClassNameIfProvide(n, parent); if (className != null) { types.add(className); } break; } } } /** * Gets the source line for the indicated line number. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Does not include the newline at the end * of the file. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public String getLine(int lineNumber) { return getSourceFile().getLine(lineNumber); } /** * Get a region around the indicated line number. The exact definition of a * region is implementation specific, but it must contain the line indicated * by the line number. A region must not start or end by a carriage return. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public Region getRegion(int lineNumber) { return getSourceFile().getRegion(lineNumber); } public String getCode() throws IOException { return getSourceFile().getCode(); } /** Returns the module to which the input belongs. */ public JSModule getModule() { return module; } /** Sets the module to which the input belongs. */ public void setModule(JSModule module) { // An input may only belong to one module. Preconditions.checkArgument( module == null || this.module == null || this.module == module); this.module = module; } public boolean isExtern() { return isExtern; } }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>SimpleOperatorType(n.getType())) break; return true; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (checkForStateChangeHelper(c, checkForNewObjects)) { return true; } } return false; } /** * Do calls to this constructor have side effects? * * @param callNode - construtor call node */ static boolean constructorCallHasSideEffects(Node callNode) { Preconditions.checkArgument( callNode.getType() == Token.NEW, "Expected NEW node, got " + Token.name(callNode.getType())); if (callNode.isNoSideEffectsCall()) { return false; } Node nameNode = callNode.getFirstChild(); if (nameNode.getType() == Token.NAME && CONSTRUCTORS_WITHOUT_SIDE_EFFECTS.contains(nameNode.getString())) { return false; } return true; } /** * Returns true if calls to this function have side effects. * * @param callNode - function call node */ static boolean functionCallHasSideEffects(Node callNode) { Preconditions.checkArgument( callNode.getType() == Token.CALL, "Expected CALL node, got " + Token.name(callNode.getType())); if (callNode.isNoSideEffectsCall()) { return false; } Node nameNode = callNode.getFirstChild(); // Built-in functions with no side effects. if (nameNode.getType() == Token.NAME) { String name = nameNode.getString(); if (name.equals("String")) { return false; } } // Functions in the "Math" namespace have no side effects. if (nameNode.getType() == Token.GETPROP && nameNode.getFirstChild().getType() == Token.NAME) { String namespaceName = nameNode.getFirstChild().getString(); if (namespaceName.equals("Math")) { return false; } } return true; } /** * Returns true if the current node's type implies side effects. * * This is a non-recursive version of the may have side effects * check; used to check wherever the current node's type is one of * the

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> keyword */ static boolean referencesThis(Node n) { return containsType(n, Token.THIS); } /** * Is this a GETPROP or GETELEM node? */ static boolean isGet(Node n) { return n.getType() == Token.GETPROP || n.getType() == Token.GETELEM; } /** * Is this a GETPROP node? */ static boolean isGetProp(Node n) { return n.getType() == Token.GETPROP; } /** * Is this a NAME node? */ static boolean isName(Node n) { return n.getType() == Token.NAME; } /** * Is this a NEW node? */ static boolean isNew(Node n) { return n.getType() == Token.NEW; } /** * Is this a VAR node? */ static boolean isVar(Node n) { return n.getType() == Token.VAR; } /** * Is this node the name of a variable being declared? * * @param n The node * @return True if {@code n} is NAME and {@code parent} is VAR */ static boolean isVarDeclaration(Node n) { // There is no need to verify that parent != null because a NAME node // always has a parent in a valid parse tree. return n.getType() == Token.NAME && n.getParent().getType() == Token.VAR; } /** * For an assignment or variable declaration get the assigned value. * @return The value node representing the new value. */ static Node getAssignedValue(Node n) { Preconditions.checkState(isName(n)); Node parent = n.getParent(); if (isVar(parent)) { return n.getFirstChild(); } else if (isAssign(parent) && parent.getFirstChild() == n) { return n.getNext(); } else { return null; } } /** * Is this a STRING node? */ static boolean isString(Node n) { return n.getType() == Token.STRING; } /** * Is this node an assignment expression statement? * * @param n The node * @return True if {@code n} is EXPR_RESULT and {@code

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>, WITH, or IF node. */ static boolean isControlStructureCodeBlock(Node parent, Node n) { switch (parent.getType()) { case Token.FOR: case Token.WHILE: case Token.LABEL: case Token.WITH: return parent.getLastChild() == n; case Token.DO: return parent.getFirstChild() == n; case Token.IF: return parent.getFirstChild() != n; case Token.TRY: return parent.getFirstChild() == n || parent.getLastChild() == n; case Token.CATCH: return parent.getLastChild() == n; case Token.SWITCH: case Token.CASE: return parent.getFirstChild() != n; case Token.DEFAULT: return true; default: Preconditions.checkState(isControlStructure(parent)); return false; } } /** * Gets the condition of an ON_TRUE / ON_FALSE CFG edge. * @param n a node with an outgoing conditional CFG edge * @return the condition node or null if the condition is not obviously a node */ static Node getConditionExpression(Node n) { switch (n.getType()) { case Token.IF: case Token.WHILE: return n.getFirstChild(); case Token.DO: return n.getLastChild(); case Token.FOR: switch (n.getChildCount()) { case 3: return null; case 4: return n.getFirstChild().getNext(); } throw new IllegalArgumentException("malformed 'for' statement " + n); case Token.CASE: return null; } throw new IllegalArgumentException(n + " does not have a condition."); } /** * @return Whether the node is of a type that contain other statements. */ static boolean isStatementBlock(Node n) { return n.getType() == Token.SCRIPT || n.getType() == Token.BLOCK; } /** * @return Whether the node is used as a statement. */ static boolean isStatement(Node n) { Node parent = n.getParent(); // It is not possible to determine definitely if a node is a statement // or not if it is not part of the AST. A FUNCTION node, for instance, // is either part of an expression (as

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> a anonymous function) or as // a statement. Preconditions.checkState(parent != null); switch (parent.getType()) { case Token.SCRIPT: case Token.BLOCK: case Token.LABEL: return true; default: return false; } } /** Whether the node is part of a switch statement. */ static boolean isSwitchCase(Node n) { return n.getType() == Token.CASE || n.getType() == Token.DEFAULT; } /** @return Whether the node is a label name. */ static boolean isLabelName(Node n) { if (n != null && n.getType() == Token.NAME) { Node parent = n.getParent(); switch (parent.getType()) { case Token.LABEL: case Token.BREAK: case Token.CONTINUE: if (n == parent.getFirstChild()) { return true; } } } return false; } /** Whether the child node is the FINALLY block of a try. */ static boolean isTryFinallyNode(Node parent, Node child) { return parent.getType() == Token.TRY && parent.getChildCount() == 3 && child == parent.getLastChild(); } /** Safely remove children while maintaining a valid node structure. */ static void removeChild(Node parent, Node node) { // Node parent = node.getParent(); if (isStatementBlock(parent) || isSwitchCase(node) || isTryFinallyNode(parent, node)) { // A statement in a block can simply be removed. parent.removeChild(node); } else if (parent.getType() == Token.VAR) { if (parent.hasMoreThanOneChild()) { parent.removeChild(node); } else { // Remove the node from the parent, so it can be reused. parent.removeChild(node); // This would leave an empty VAR, remove the VAR itself. removeChild(parent.getParent(), parent); } } else if (node.getType() == Token.BLOCK) { // Simply empty the block. This maintains source location and // "synthetic"-ness. node.detachChildren(); } else if (parent.getType() == Token.LABEL && node == parent.getLastChild()) { // Remove the node from the parent,

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> so it can be reused. parent.removeChild(node); // A LABEL without children can not be referred to, remove it. removeChild(parent.getParent(), parent); } else if (parent.getType() == Token.FOR && parent.getChildCount() == 4) { // Only Token.FOR can have an Token.EMPTY other control structure // need something for the condition. Others need to be replaced // or the structure removed. Preconditions.checkState(parent.getType() == Token.FOR && parent.getChildCount() == 4); parent.replaceChild(node, new Node(Token.EMPTY)); } else { throw new IllegalStateException("Invalid attempt to remove node: " + node.toString() + " of "+ parent.toString()); } } /** * Merge a block with its parent block. * @return Whether the block was removed. */ static boolean tryMergeBlock(Node block) { Preconditions.checkState(block.getType() == Token.BLOCK); Node parent = block.getParent(); // Try to remove the block if its parent is a block/script or if its // parent is label and it has exactly one child. if (NodeUtil.isStatementBlock(parent)) { Node previous = block; while (block.hasChildren()) { Node child = block.removeFirstChild(); parent.addChildAfter(child, previous); previous = child; } parent.removeChild(block); return true; } else if (parent.getType() == Token.LABEL && block.hasOneChild()) { parent.replaceChild(block, block.removeFirstChild()); return true; } else { return false; } } /** * Is this a CALL node? */ static boolean isCall(Node n) { return n.getType() == Token.CALL; } /** * Is this a FUNCTION node? */ static boolean isFunction(Node n) { return n.getType() == Token.FUNCTION; } /** * Return a BLOCK node for the given FUNCTION node. */ static Node getFunctionBody(Node fn) { Preconditions.checkArgument(isFunction(fn)); return fn.getLastChild(); } /** * Is this a THIS node? */ static boolean isThis(Node node) {

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> return node.getType() == Token.THIS; } /** * Is this node or any of its children a CALL? */ static boolean containsCall(Node n) { return containsType(n, Token.CALL); } /** * Is this node a function declaration? A function declaration is a function * that has a name that is added to the current scope (i.e. a function that * is not anonymous; see {@link #isFunctionAnonymous}). */ static boolean isFunctionDeclaration(Node n) { return n.getType() == Token.FUNCTION && !isFunctionAnonymous(n); } /** * Is this node an anonymous function? An anonymous function is one that has * either no name or a name that is not added to the current scope (see * {@link #isFunctionAnonymous}). */ static boolean isAnonymousFunction(Node n) { return n.getType() == Token.FUNCTION && isFunctionAnonymous(n); } /** * Is a FUNCTION node an anonymous function? An anonymous function is one that * has either no name or a name that is not added to the current scope. * * <p>Some examples of anonymous functions: * <pre> * function () {} * (function f() {})() * [ function f() {} ] * var f = function f() {}; * for (function f() {};;) {} * </pre> * * <p>Some examples of functions that are <em>not</em> anonymous: * <pre> * function f() {} * if (x); else function f() {} * for (;;) { function f() {} } * </pre> * * @param n A FUNCTION node * @return Whether n is an anonymous function */ static boolean isFunctionAnonymous(Node n) { return !isStatement(n); } /** * Determines if a function takes a variable number of arguments by * looking for references to the "arguments" var_args object. */ static boolean isVarArgsFunction(Node function) { Preconditions.checkArgument(isFunction(function)); return NodeUtil.isNameReferenced( function.getLastChild(), "arguments", Predicates.<Node>not(new NodeUtil.MatchNodeType(Token.FUNCTION))); } /** * @return Whether node

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> Token.VAR, Node.newString(Token.NAME, nameNode.getString())); copyNameAnnotations(nameNode, var.getFirstChild()); parent.addChildToFront(var); } } /** * Copy any annotations that follow a named value. * @param source * @param destination */ static void copyNameAnnotations(Node source, Node destination) { if (source.getBooleanProp(Node.IS_CONSTANT_NAME)) { destination.putBooleanProp(Node.IS_CONSTANT_NAME, true); } } /** * Gets a Node at the top of the current scope where we can add new var * declarations as children. */ private static Node getAddingRoot(Node n) { Node addingRoot = null; Node ancestor = n; while (null != (ancestor = ancestor.getParent())) { int type = ancestor.getType(); if (type == Token.SCRIPT) { addingRoot = ancestor; break; } else if (type == Token.FUNCTION) { addingRoot = ancestor.getLastChild(); break; } } // make sure that the adding root looks ok Preconditions.checkState(addingRoot.getType() == Token.BLOCK || addingRoot.getType() == Token.SCRIPT); Preconditions.checkState(addingRoot.getFirstChild() == null || addingRoot.getFirstChild().getType() != Token.SCRIPT); return addingRoot; } /** Creates function name(params_0, ..., params_n) { body }. */ public static FunctionNode newFunctionNode(String name, List<Node> params, Node body, int lineno, int charno) { Node parameterParen = new Node(Token.LP, lineno, charno); for (Node param : params) { parameterParen.addChildToBack(param); } FunctionNode function = new FunctionNode(name, lineno, charno); function.addChildrenToBack( Node.newString(Token.NAME, name, lineno, charno)); function.addChildToBack(parameterParen); function.addChildToBack(body); return function; } /** * Creates a node representing a qualified name. * * @param name A qualified name (e.g. "foo" or "foo.bar.baz") * @param lineno The source line offset

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> return total; } /** * Interface for use with the visit method. * @see #visit */ static interface Visitor { void visit(Node node); } /** * A pre-order traversal, calling Vistor.visit for each child matching * the predicate. */ static void visitPreOrder(Node node, Visitor vistor, Predicate<Node> traverseChildrenPred) { vistor.visit(node); if (traverseChildrenPred.apply(node)) { for (Node c = node.getFirstChild(); c != null; c = c.getNext()) { visitPreOrder(c, vistor, traverseChildrenPred); } } } /** * A post-order traversal, calling Vistor.visit for each child matching * the predicate. */ static void visitPostOrder(Node node, Visitor vistor, Predicate<Node> traverseChildrenPred) { if (traverseChildrenPred.apply(node)) { for (Node c = node.getFirstChild(); c != null; c = c.getNext()) { visitPostOrder(c, vistor, traverseChildrenPred); } } vistor.visit(node); } /** * @return Whether a TRY node has a finally block. */ static boolean hasFinally(Node n) { Preconditions.checkArgument(n.getType() == Token.TRY); return n.getChildCount() == 3; } /** * @return The BLOCK node containing the CATCH node (if any) * of a TRY. */ static Node getCatchBlock(Node n) { Preconditions.checkArgument(n.getType() == Token.TRY); return n.getFirstChild().getNext(); } /** * @return Whether BLOCK (from a TRY node) contains a CATCH. * @see NodeUtil#getCatchBlock */ static boolean hasCatchHandler(Node n) { Preconditions.checkArgument(n.getType() == Token.BLOCK); return n.hasChildren() && n.getFirstChild().getType() == Token.CATCH; } /** * @param fnNode The function. * @return The Node containing the Function parameters. */ static Node getFnParameters(Node fnNode) { // Function NODE: [ FUNCTION -> NAME, LP -> ARG1,

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> ARG2, ... ] Preconditions.checkArgument(fnNode.getType() == Token.FUNCTION); return fnNode.getFirstChild().getNext(); } /** * Returns true if a name node represents a constant variable. * * <p>Determining whether a variable is constant has three steps: * <ol> * <li>In CodingConventionAnnotator, any name that matches the * {@link CodingConvention#isConstant(String)} is annotated with an * IS_CONSTANT_NAME property. * <li>The normalize pass renames any variable with the IS_CONSTANT_NAME * annotation and that is initialized to a constant value with * a variable name inlucding $$constant. * <li>Return true here if the variable includes $$constant in its name. * </ol> * * @param node A NAME or STRING node * @return True if the variable is constant */ static boolean isConstantName(Node node) { return node.getString().contains(CONSTANT_MARKER); } /** * @param nameNode A name node * @return The JSDocInfo for the name node */ static JSDocInfo getInfoForNameNode(Node nameNode) { JSDocInfo info = null; Node parent = null; if (nameNode != null) { info = nameNode.getJSDocInfo(); parent = nameNode.getParent(); } if (info == null && parent != null && ((parent.getType() == Token.VAR && parent.hasOneChild()) || parent.getType() == Token.FUNCTION)) { info = parent.getJSDocInfo(); } return info; } /** * @param n The node. * @return The source name property on the node or its ancestors. */ static String getSourceName(Node n) { String sourceName = null; while (sourceName == null && n != null) { sourceName = (String) n.getProp(Node.SOURCENAME_PROP); n = n.getParent(); } return sourceName; } }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>/* * Copyright 2004 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.StringUtil; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; /** * CodeGenerator generates codes from a parse tree, sending it to the specified * CodeConsumer. * * * */ class CodeGenerator { private final CodeConsumer cc; CodeGenerator(CodeConsumer consumer) { cc = consumer; } void add(String str) { cc.add(str); } private void addIdentifier(String identifier) { cc.addIdentifier(identifierEscape(identifier)); } void add(Node n) { add(n, Context.OTHER); } void add(Node n, Context context) { if (!cc.continueProcessing()) { return; } int type = n.getType(); String opstr = NodeUtil.opToStr(type); int childCount = n.getChildCount(); Node first = n.getFirstChild(); Node last = n.getLastChild(); // Handle all binary operators if (opstr != null && first != last) { Preconditions.checkState(childCount == 2); int p = NodeUtil.precedence(type); addLeftExpr(first, p, context); cc.addOp(opstr, true); // For right-hand-side of operations, only pass context if it's // the IN_FOR_INIT_CLAUSE one. Context rhsContext = getContext

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>ForNoInOperator(context); // Handle associativity. // e.g. if the parse tree is a * (b * c), // we can simply generate a * b * c. if (last.getType() == type && NodeUtil.isAssociative(type)) { addExpr(last, p, rhsContext); } else if (NodeUtil.isAssignmentOp(n) && NodeUtil.isAssignmentOp(last)) { // Assignments are the only right-associative binary operators addExpr(last, p, rhsContext); } else { addExpr(last, p + 1, rhsContext); } return; } cc.startSourceMapping(n); switch (type) { case Token.TRY: { Preconditions.checkState(first.getNext().getType() == Token.BLOCK && first.getNext().getChildCount() <= 1); Preconditions.checkState(childCount >= 2 && childCount <= 3); add("try"); add(first, Context.PRESERVE_BLOCK); // second child contains the catch block, or nothing if there // isn't a catch block Node catchblock = first.getNext().getFirstChild(); if (catchblock != null) { add(catchblock); } if (childCount == 3) { add("finally"); add(last, Context.PRESERVE_BLOCK); } break; } case Token.CATCH: Preconditions.checkState(childCount == 3); if (first.getNext().getType() != Token.EMPTY) { throw new Error("Catch conditions not suppored because I think" + " that it may be a netscape only feature."); } add("catch("); add(first); add(")"); add(last, Context.PRESERVE_BLOCK); break; case Token.THROW: Preconditions.checkState(childCount == 1); add("throw"); add(first); // Must have a ';' after a throw statement, otherwise safari can't // parse this. cc.endStatement(true); break; case Token.RETURN: add("return"); if (childCount == 1) { add(first); } else { Preconditions.checkState(childCount == 0);

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> } cc.endStatement(); break; case Token.VAR: if (first != null) { add("var "); addList(first, false, getContextForNoInOperator(context)); } break; case Token.NAME: if (first == null || first.getType() == Token.EMPTY) { addIdentifier(n.getString()); } else { Preconditions.checkState(childCount == 1); addIdentifier(n.getString()); cc.addOp("=", true); if (first.getType() == Token.COMMA) { addExpr(first, NodeUtil.precedence(Token.ASSIGN)); } else { // Add expression, consider nearby code at lowest level of // precedence. addExpr(first, 0, getContextForNoInOperator(context)); } } break; case Token.ARRAYLIT: add("["); addList(first, (int[]) n.getProp(Node.SKIP_INDEXES_PROP)); add("]"); break; case Token.LP: add("("); addList(first); add(")"); break; case Token.COMMA: addList(first, false, context); break; case Token.NUMBER: Preconditions.checkState(childCount == 0); cc.addNumber(n.getDouble()); break; case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: case Token.NEG: { // All of these unary operators are right-associative Preconditions.checkState(childCount == 1); cc.addOp(NodeUtil.opToStrNoFail(type), false); addExpr(first, NodeUtil.precedence(type)); break; } case Token.HOOK: { Preconditions.checkState(childCount == 3); int p = NodeUtil.precedence(type); addLeftExpr(first, p + 1, context); cc.addOp("?", true); addExpr(first.getNext(), p); cc.addOp(":", true); addExpr(last, p); break; } case Token.REGEXP: if (first.getType() != Token.STRING || last.getType() !=

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> Token.STRING) { throw new Error("Expected children to be strings"); } String regexp = regexpEscape(first.getString()); // I only use one .add because whitespace matters if (childCount == 2) { add(regexp + last.getString()); } else { Preconditions.checkState(childCount == 1); add(regexp); } break; case Token.GET_REF: add(first); break; case Token.REF_SPECIAL: Preconditions.checkState(childCount == 1); add(first); add("."); add((String) n.getProp(Node.NAME_PROP)); break; case Token.FUNCTION: Preconditions.checkState(childCount == 3); boolean funcNeedsParens = (context == Context.START_OF_EXPR); if (funcNeedsParens) { add("("); } add("function"); add(first); add(first.getNext()); add(last, Context.PRESERVE_BLOCK); cc.endFunction(context == Context.STATEMENT); if (funcNeedsParens) { add(")"); } break; case Token.SCRIPT: case Token.BLOCK: { boolean stripBlock = n.isSyntheticBlock() || ((context != Context.PRESERVE_BLOCK) && (n.getChildCount() < 2)); if (!stripBlock) { cc.beginBlock(); } for (Node c = first; c != null; c = c.getNext()) { add(c, Context.STATEMENT); // VAR doesn't include ';' since it gets used in expressions if (c.getType() == Token.VAR) { cc.endStatement(); } if (c.getType() == Token.FUNCTION) { cc.maybeLineBreak(); } // Prefer to break lines in between top-level statements // because top level statements are more homogeneous. if (type == Token.SCRIPT) { cc.notePreferredLineBreak(); } } if (!stripBlock) { cc.endBlock(context == Context.STATEMENT); } break; } case Token.FOR: if (childCount == 4) { add("for("); if (first.getType

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>() == Token.VAR) { add(first, Context.IN_FOR_INIT_CLAUSE); } else { addExpr(first, 0, Context.IN_FOR_INIT_CLAUSE); } add(";"); add(first.getNext()); add(";"); add(first.getNext().getNext()); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } else { Preconditions.checkState(childCount == 3); add("for("); add(first); add("in"); add(first.getNext()); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } break; case Token.DO: Preconditions.checkState(childCount == 2); add("do"); addNonEmptyExpression(first, Context.OTHER, false); add("while("); add(last); add(")"); cc.endStatement(); break; case Token.WHILE: Preconditions.checkState(childCount == 2); add("while("); add(first); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); break; case Token.EMPTY: Preconditions.checkState(childCount == 0); break; case Token.GETPROP: { Preconditions.checkState(childCount == 2); Preconditions.checkState(last.getType() == Token.STRING); boolean needsParens = (first.getType() == Token.NUMBER); if (needsParens) { add("("); } addLeftExpr(first, NodeUtil.precedence(type), context); if (needsParens) { add(")"); } add("."); addIdentifier(last.getString()); break; } case Token.GETELEM: Preconditions.checkState(childCount == 2); addLeftExpr(first, NodeUtil.precedence(type), context); add("["); add(first.getNext()); add("]"); break; case Token.WITH: Preconditions.checkState(childCount == 2); add("with("); add(first); add(")"); addNonEmptyExpression( last, getContext

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>ForNonEmptyExpression(context), false); break; case Token.INC: case Token.DEC: { Preconditions.checkState(childCount == 1); String o = type == Token.INC ? "++" : "--"; int postProp = n.getIntProp(Node.INCRDECR_PROP, 0); // A non-zero post-prop value indicates a post inc/dec, default of zero // is a pre-inc/dec. if (postProp != 0) { addLeftExpr(first, NodeUtil.precedence(type), context); cc.addOp(o, false); } else { cc.addOp(o, false); add(first); } break; } case Token.CALL: addLeftExpr(first, NodeUtil.precedence(type), context); add("("); addList(first.getNext()); add(")"); break; case Token.IF: boolean hasElse = childCount == 3; boolean ambiguousElseClause = context == Context.BEFORE_DANGLING_ELSE && !hasElse; if (ambiguousElseClause) { cc.beginBlock(); } add("if("); add(first); add(")"); if (hasElse) { addNonEmptyExpression( first.getNext(), Context.BEFORE_DANGLING_ELSE, false); add("else"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } else { addNonEmptyExpression(first.getNext(), Context.OTHER, false); Preconditions.checkState(childCount == 2); } if (ambiguousElseClause) { cc.endBlock(); } break; case Token.NULL: case Token.THIS: case Token.FALSE: case Token.TRUE: Preconditions.checkState(childCount == 0); add(Node.tokenToName(type)); break; case Token.CONTINUE: Preconditions.checkState(childCount <= 1); add("continue"); if (childCount == 1) { add(" "); add(first); } cc.endStatement(); break; case Token.DEBUGGER: Preconditions.checkState(childCount == 0);

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> add("debugger"); cc.endStatement(); break; case Token.BREAK: Preconditions.checkState(childCount <= 1); add("break"); if (childCount == 1) { add(" "); add(first); } cc.endStatement(); break; case Token.EXPR_VOID: // TODO(johnlenz): Enable this exception once the external users of // CodePrinter have been corrected. // throw new Error("EXPR_VOID should not be used in this codebase."); case Token.EXPR_RESULT: Preconditions.checkState(childCount == 1); add(first, Context.START_OF_EXPR); cc.endStatement(); break; case Token.NEW: add("new "); int precedence = NodeUtil.precedence(type); // If the first child contains a CALL, then claim higher precedence // to force parens. Otherwise, when parsed, NEW will bind to the // first viable parens if (NodeUtil.containsCall(first)) { precedence = NodeUtil.precedence(first.getType()) + 1; } addExpr(first, precedence); // '()' is optional when no arguments are present Node next = first.getNext(); if (next != null) { add("("); addList(next); add(")"); } break; case Token.STRING: Preconditions.checkState(childCount == 0); add(jsString(n.getString())); break; case Token.DELPROP: Preconditions.checkState(childCount == 1); add("delete "); add(first); break; case Token.OBJECTLIT: { Preconditions.checkState(childCount % 2 == 0); boolean needsParens = (context == Context.START_OF_EXPR); if (needsParens) { add("("); } add("{"); for (Node c = first; c != null; c = c.getNext().getNext()) { if (c != first) { cc.listSeparator(); } // Object literal property names don't have to be quoted if they are // not JavaScript keywords if (c.getType() == Token.STRING && !TokenStream.isKeyword(c.getString()) && TokenStream

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>.isJSIdentifier(c.getString()) && // do not encode literally any non-literal characters that were // unicode escaped. NodeUtil.isLatin(c.getString())) { add(c.getString()); } else { addExpr(c, 1); } add(":"); addExpr(c.getNext(), 1); } add("}"); if (needsParens) { add(")"); } break; } case Token.SWITCH: add("switch("); add(first); add(")"); cc.beginBlock(); addAllSiblings(first.getNext()); cc.endBlock(context == Context.STATEMENT); break; case Token.CASE: Preconditions.checkState(childCount == 2); add("case "); add(first); addCaseBody(last); break; case Token.DEFAULT: Preconditions.checkState(childCount == 1); add("default"); addCaseBody(first); break; case Token.LABEL: Preconditions.checkState(childCount == 2); add(first); add(":"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), true); break; // This node is auto generated in anonymous functions and should just get // ignored for our purposes. case Token.SETNAME: break; default: throw new Error("Unknown type " + type + "\n" + n.toStringTree()); } cc.endSourceMapping(n); } /** * Adds a block or expression, substituting a VOID with an empty statement. * This is used for "for (...);" and "if (...);" type statements. * * @param n The node to print. * @param context The context to determine how the node should be printed. */ private void addNonEmptyExpression( Node n, Context context, boolean allowNonBlockChild) { Node nodeToProcess = n; if (!allowNonBlockChild && n.getType() != Token.BLOCK) { // TODO(johnlenz) : Enable this when the JsMinifier is corrected. // throw new Error("Missing BLOCK child."); } // Strip unneeded blocks, that is blocks with <2 children. if (n.getType() == Token.

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> while (s.getParent() != null) { num += s.getVarCount(); s = s.getParent(); } return num; } /** * Returns whether this is a global variable. */ public boolean isGlobal() { return scope.isGlobal(); } /** * Returns whether this is a local variable. */ public boolean isLocal() { return scope.isLocal(); } /** * Returns whether this is defined in an extern file. */ boolean isExtern() { return input == null || input.isExtern(); } /** * Returns {@code true} if the variable is declared as a constant, * based on the value reported by {@code NodeUtil}. */ public boolean isConst() { return NodeUtil.isConstantName(nameNode); } /** * Returns {@code true} if the variable is declared as a define. * A variable is a define if it is annotaed by {@code @define}. */ public boolean isDefine() { return isDefine; } public Node getInitialValue() { Node parent = getParentNode(); return parent.getType() == Token.FUNCTION ? parent : nameNode.getFirstChild(); } /** * Gets this variable's type. To know whether this type has been inferred, * see {@code #isInferred()}. */ public JSType getType() { return type; } /** * Returns the name node that produced this variable. */ public Node getNameNode() { return nameNode; } /** * Gets the JSDocInfo for the variable. */ public JSDocInfo getJSDocInfo() { return info; } /** * Sets this variable's type. * @throws IllegalStateException if the variable's type is not inferred */ void setType(JSType type) { Preconditions.checkState(isTypeInferred()); this.type = type; } /** * Returns whether this variable's type is inferred. To get the variable's * type, see {@link #getType()}. */ public boolean isTypeInferred() { return typeInferred; } public String getInputName() { if (input == null) return "<non-file>"; else return input.getName(); }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> public boolean isNoShadow() { if (info != null && info.isNoShadow()) { return true; } else { return false; } } @Override public boolean equals(Object other) { if (!(other instanceof Var)) { return false; } Var otherVar = (Var) other; return otherVar.nameNode == nameNode; } @Override public int hashCode() { return nameNode.hashCode(); } @Override public String toString() { return "Scope.Var " + name; } } /** * Creates a Scope given the parent Scope and the root node of the scope. * @param parent The parent Scope. Cannot be null. * @param rootNode Typically the FUNCTION node. */ Scope(Scope parent, Node rootNode) { Preconditions.checkNotNull(parent); Preconditions.checkArgument(rootNode != parent.rootNode); this.parent = parent; this.rootNode = rootNode; JSType nodeType = rootNode.getJSType(); if (nodeType != null && nodeType instanceof FunctionType) { thisType = ((FunctionType) nodeType).getTypeOfThis(); } else { thisType = parent.thisType; } this.isBottom = false; } /** * Creates a global Scope. * @param rootNode Typically the global BLOCK node. */ Scope(Node rootNode, AbstractCompiler compiler) { this.parent = null; this.rootNode = rootNode; thisType = compiler.getTypeRegistry().getNativeObjectType(GLOBAL_THIS); this.isBottom = false; } /** * Creates a empty Scope (bottom of the lattice). * @param rootNode Typically a FUNCTION node or the global BLOCK node. * @param thisType the type of {@code this} in this scope */ Scope(Node rootNode, ObjectType thisType) { this.parent = null; this.rootNode = rootNode; this.thisType = thisType; this.isBottom = true; } /** Whether this is the bottom of the lattice. */ boolean isBottom() { return isBottom; } /** * Gets the container node of the scope. This is typically the FUNCTION * node or the global BLOCK/SCRIPT node. */

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> public Node getRootNode() { return rootNode; } public Scope getParent() { return parent; } Scope getGlobalScope() { Scope result = this; while (result.getParent() != null) { result = result.getParent(); } return result; } @Override public StaticScope<JSType> getParentScope() { return parent; } /** * Gets the type of {@code this} in the current scope. */ public ObjectType getTypeOfThis() { return thisType; } /** * Declares a variable whose type is inferred. * * @param name name of the variable * @param nameNode the NAME node declaring the variable * @param type the variable's type * @param input the input in which this variable is defined. */ Var declare(String name, Node nameNode, JSType type, CompilerInput input) { return declare(name, nameNode, type, input, true); } /** * Declares a variable. * * @param name name of the variable * @param nameNode the NAME node declaring the variable * @param type the variable's type * @param input the input in which this variable is defined. * @param inferred Whether this variable's type is inferred (as opposed * to declared). */ Var declare(String name, Node nameNode, JSType type, CompilerInput input, boolean inferred) { Preconditions.checkState(name != null && name.length() > 0); // Make sure that it's declared only once Preconditions.checkState(vars.get(name) == null); Var var = new Var(inferred); var.name = name; var.nameNode = nameNode; var.type = type; var.referenced = false; var.scope = this; var.index = vars.size(); var.input = input; // native variables do not have a name node. // TODO(user): make Var abstract and have NativeVar, NormalVar. JSDocInfo info = NodeUtil.getInfoForNameNode(nameNode); var.isDefine = info != null && info.isDefine(); var.info = info; vars.put(name, var); return var; } /**

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> * Undeclares a variable, to be used when the compiler optimizes out * a variable and removes it from the scope. */ void undeclare(Var var) { Preconditions.checkState(var.scope == this); Preconditions.checkState(vars.get(var.name) == var); vars.remove(var.name); } public StaticSlot<JSType> getSlot(String name) { return getVar(name); } public StaticSlot<JSType> getOwnSlot(String name) { return vars.get(name); } /** * Returns the variable, may be null */ public Var getVar(String name) { Var var = vars.get(name); if (var != null) { return var; } else if (parent != null) { // Recurse up the parent Scope return parent.getVar(name); } else { return null; } } /** * Returns true if a variable is declared. */ public boolean isDeclared(String name, boolean recurse) { Scope scope = this; if (scope.vars.containsKey(name)) return true; if (scope.parent != null && recurse) { return scope.parent.isDeclared(name, recurse); } return false; } /** * Return an iterator over all of the variables declared in this scope. */ public Iterator<Var> getVars() { return vars.values().iterator(); } /** * Returns number of variables in this scope */ public int getVarCount() { return vars.size(); } /** * Returns whether this is the global scope. */ public boolean isGlobal() { return parent == null; } /** * Returns whether this is a local scope (i.e. not the global scope). */ public boolean isLocal() { return !isGlobal(); } }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>(compiler, root); } for (Name name : namespace.getNameForest()) { checkDescendantNames(name, name.globalSets + name.localSets > 0); } } /** * Checks to make sure all the descendants of a name are defined if they * are referenced. * * @param name A global name. * @param nameIsDefined If true, {@code name} is defined. Otherwise, it's * undefined, and any references to descendant names should emit warnings. */ private void checkDescendantNames(Name name, boolean nameIsDefined) { if (name.props != null) { for (Name prop : name.props) { // if the ancestor of a property is not defined, then we should emit // warnings for all references to the property. boolean propIsDefined = false; if (nameIsDefined) { // if the ancestor of a property is defined, then let's check that // the property is also explicitly defined if it needs to be. propIsDefined = (!propertyMustBeInitializedByFullName(prop) || prop.globalSets + prop.localSets > 0); } validateName(prop, propIsDefined); checkDescendantNames(prop, propIsDefined); } } } private void validateName(Name name, boolean isDefined) { // If the name is not defined, emit warnings for each reference. While // we're looking through each reference, check all the module dependencies. Ref declaration = name.declaration; if (!isDefined) { if (declaration != null) { reportRefToUndefinedName(name, declaration); } } if (name.refs != null) { JSModuleGraph moduleGraph = compiler.getModuleGraph(); for (Ref ref : name.refs) { if (!isDefined) { reportRefToUndefinedName(name, ref); } else { if (declaration != null && ref.module != declaration.module && !moduleGraph.dependsOn(ref.module, declaration.module)) { reportBadModuleReference(name, ref); } } } } } private void reportBadModuleReference(Name name, Ref ref) { compiler.report( JSError.make(ref.sourceName, ref.node, STRICT_MODULE

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>_DEP_QNAME, ref.module.getName(), name.declaration.module.getName(), name.fullName())); } private void reportRefToUndefinedName(Name name, Ref ref) { // grab the highest undefined ancestor to output in the warning message. while (name.parent != null && name.parent.globalSets + name.parent.localSets == 0) { name = name.parent; } compiler.report( JSError.make(ref.sourceName, ref.node, level, UNDEFINED_NAME_WARNING, name.fullName())); } /** * Checks whether the given name is a property, and whether that property * must be initialized with its full qualified name. */ private static boolean propertyMustBeInitializedByFullName(Name name) { // If an object literal in the global namespace is never aliased, // then all of its properties must be defined using its full qualified // name. This implies that its properties must all be in the global // namespace as well. // // The same is not true for FUNCTION and OTHER types, because their // implicit prototypes have properties that are not captured by the global // namespace. return name.parent != null && name.parent.aliasingGets == 0 && name.parent.type == Name.Type.OBJECTLIT; } }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>", getterType, false); functionType.defineDeclaredProperty("instance_", objectType, false); } @Override public String getGlobalObject() { return "goog.global"; } @Override public boolean allowsVariableRedeclaration( Scope scope, String name, Node parent) { return !scope.isGlobal(); } private final Set<String> propertyTestFunctions = ImmutableSet.of( "goog.isDef", "goog.isNull", "goog.isDefAndNotNull", "goog.isString", "goog.isNumber", "goog.isBoolean", "goog.isFunction", "goog.isArray", "goog.isObject"); @Override public boolean isPropertyTestFunction(Node call) { Preconditions.checkArgument(call.getType() == Token.CALL); return propertyTestFunctions.contains( call.getFirstChild().getQualifiedName()); } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) { Preconditions.checkArgument(callNode.getType() == Token.CALL); Node callName = callNode.getFirstChild(); if (!"goog.reflect.object".equals(callName.getQualifiedName()) || callName.getChildCount() != 2) { return null; } Node typeNode = callName.getNext(); if (!typeNode.isQualifiedName()) { return null; } Node objectNode = typeNode.getNext(); if (objectNode.getType() != Token.OBJECTLIT) { t.getCompiler().report(JSError.make(t.getSourceName(), callNode, OBJECTLIT_EXPECTED)); return null; } return new ObjectLiteralCast(typeNode.getQualifiedName(), typeNode.getNext()); } }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> type = nodeType; parent = null; sourcePosition = -1; } public Node(int nodeType, Node child) { Preconditions.checkArgument(child.parent == null, "new child has existing parent"); Preconditions.checkArgument(child.next == null, "new child has existing sibling"); type = nodeType; parent = null; first = last = child; child.next = null; child.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node right) { Preconditions.checkArgument(left.parent == null, "first new child has existing parent"); Preconditions.checkArgument(left.next == null, "first new child has existing sibling"); Preconditions.checkArgument(right.parent == null, "second new child has existing parent"); Preconditions.checkArgument(right.next == null, "second new child has existing sibling"); type = nodeType; parent = null; first = left; last = right; left.next = right; left.parent = this; right.next = null; right.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node mid, Node right) { Preconditions.checkArgument(left.parent == null); Preconditions.checkArgument(left.next == null); Preconditions.checkArgument(mid.parent == null); Preconditions.checkArgument(mid.next == null); Preconditions.checkArgument(right.parent == null); Preconditions.checkArgument(right.next == null); type = nodeType; parent = null; first = left; last = right; left.next = mid; left.parent = this; mid.next = right; mid.parent = this; right.next = null; right.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node mid, Node mid2, Node right) { Preconditions.checkArgument(left.parent == null); Preconditions.checkArgument(left.next == null); Preconditions.checkArgument(mid.parent == null); Preconditions.checkArgument(mid.next == null); Preconditions.checkArgument(mid2.parent == null);

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> Preconditions.checkArgument(mid2.next == null); Preconditions.checkArgument(right.parent == null); Preconditions.checkArgument(right.next == null); type = nodeType; parent = null; first = left; last = right; left.next = mid; left.parent = this; mid.next = mid2; mid.parent = this; mid2.next = right; mid2.parent = this; right.next = null; right.parent = this; sourcePosition = -1; } public Node(int nodeType, int lineno, int charno) { type = nodeType; parent = null; sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node child, int lineno, int charno) { this(nodeType, child); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node left, Node right, int lineno, int charno) { this(nodeType, left, right); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node left, Node mid, Node right, int lineno, int charno) { this(nodeType, left, mid, right); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node left, Node mid, Node mid2, Node right, int lineno, int charno) { this(nodeType, left, mid, mid2, right); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node[] children, int lineno, int charno) { this(nodeType, children); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node[] children) { this.type = nodeType; parent = null; if (children.length != 0) { this.first = children[0]; this.last = children[children.length - 1]; for (int i = 1; i < children.length; i++) { if (null != children[i - 1].next) { // fail early on loops.

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> implies same node in array twice throw new IllegalArgumentException("duplicate child"); } children[i - 1].next = children[i]; Preconditions.checkArgument(children[i - 1].parent == null); children[i - 1].parent = this; } Preconditions.checkArgument( children[children.length - 1].parent == null); children[children.length - 1].parent = this; if (null != this.last.next) { // fail early on loops. implies same node in array twice throw new IllegalArgumentException("duplicate child"); } } } public static Node newNumber(double number) { return new NumberNode(number); } public static Node newNumber(double number, int lineno, int charno) { return new NumberNode(number, lineno, charno); } public static Node newString(String str) { return new StringNode(Token.STRING, str); } public static Node newString(int type, String str) { return new StringNode(type, str); } public static Node newString(String str, int lineno, int charno) { return new StringNode(Token.STRING, str, lineno, charno); } public static Node newString(int type, String str, int lineno, int charno) { return new StringNode(type, str, lineno, charno); } public int getType() { return type; } public void setType(int type) { this.type = type; } public boolean hasChildren() { return first != null; } public Node getFirstChild() { return first; } public Node getLastChild() { return last; } public Node getNext() { return next; } public Node getChildBefore(Node child) { if (child == first) return null; Node n = first; while (n.next != child) { n = n.next; if (n == null) throw new RuntimeException("node is not a child"); } return n; } public Node getChildAtIndex(int i) { Node n = first; while (i > 0) { n = n.next; i--; } return n; }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> public Node getLastSibling() { Node n = this; while (n.next != null) { n = n.next; } return n; } public void addChildToFront(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = first; first = child; if (last == null) { last = child; } } public void addChildToBack(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = null; if (last == null) { first = last = child; return; } last.next = child; last = child; } public void addChildrenToFront(Node children) { for (Node child = children; child != null; child = child.next) { Preconditions.checkArgument(child.parent == null); child.parent = this; } Node lastSib = children.getLastSibling(); lastSib.next = first; first = children; if (last == null) { last = lastSib; } } public void addChildrenToBack(Node children) { for (Node child = children; child != null; child = child.next) { // Hmmm... IRFactory doesn't remove before calling this. Preconditions.checkArgument(child.parent == null); child.parent = this; } if (last != null) { last.next = children; } last = children.getLastSibling(); if (first == null) { first = children; } } /** * Add 'child' before 'node'. */ public void addChildBefore(Node newChild, Node node) { Preconditions.checkArgument(node != null, "The existing child node of the parent should not be null."); Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a parent."); if (first == node) { newChild.parent = this;

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> newChild.next = first; first = newChild; return; } Node prev = getChildBefore(node); addChildAfter(newChild, prev); } /** * Add 'child' after 'node'. */ public void addChildAfter(Node newChild, Node node) { Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a parent."); newChild.parent = this; newChild.next = node.next; node.next = newChild; if (last == node) { last = newChild; } } /** * Detach a child from its parent and siblings. */ public void removeChild(Node child) { Node prev = getChildBefore(child); if (prev == null) first = first.next; else prev.next = child.next; if (child == last) last = prev; child.next = null; child.parent = null; } /** * Detaches child from Node and replaces it with newChild. */ public void replaceChild(Node child, Node newChild) { Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a parent."); // Copy over important information. newChild.copyInformationFrom(child); newChild.next = child.next; newChild.parent = this; if (child == first) { first = newChild; } else { Node prev = getChildBefore(child); prev.next = newChild; } if (child == last) last = newChild; child.next = null; child.parent = null; } public void replaceChildAfter(Node prevChild, Node newChild) { Preconditions.checkArgument(prevChild.parent == this, "prev is not a child of this node."); Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> for (Node child : n.children()) { ...</pre> */ public Iterable<Node> children() { if (first == null) { return Collections.emptySet(); } else { return new SiblingNodeIterable(first); } } /** * <p>Return an iterable object that iterates over this nodes's siblings. * The iterator does not support the optional operation * {@link Iterator#remove()}.</p> * * <p>To iterate over a node's siblings, one can write</p> * <pre>Node n = ...; * for (Node sibling : n.siblings()) { ...</pre> */ public Iterable<Node> siblings() { return new SiblingNodeIterable(this); } /** * @see Node#siblings() */ private static final class SiblingNodeIterable implements Iterable<Node>, Iterator<Node> { private final Node start; private Node current; private boolean used; SiblingNodeIterable(Node start) { this.start = start; this.current = start; this.used = false; } public Iterator<Node> iterator() { if (!used) { used = true; return this; } else { // We have already used the current object as an iterator; // we must create a new SiblingNodeIterable based on this // iterable's start node. // // Since the primary use case for Node.children is in for // loops, this branch is extremely unlikely. return (new SiblingNodeIterable(start)).iterator(); } } public boolean hasNext() { return current != null; } public Node next() { if (current == null) { throw new NoSuchElementException(); } try { return current; } finally { current = current.getNext(); } } public void remove() { throw new UnsupportedOperationException(); } } //========================================================================== // Accessors public Node getParent() { return parent; } /** * Gets the ancestor node relative to this. * @param level 0 = this, 1 = the parent, etc. */ public Node getAncestor(int level) { Preconditions.checkArgument(level >= 0); Node node = this; while(

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>: return getFirstChild().isUnscopedQualifiedName(); default: return false; } } //========================================================================== // Mutators /** * Removes this node from its parent. Equivalent to: * node.getParent().removeChild(); */ public Node detachFromParent() { Preconditions.checkState(parent != null); parent.removeChild(this); return this; } /** * Removes the first child of Node. Equivalent to: * node.removeChild(node.getFirstChild()); * @return The removed Node. */ public Node removeFirstChild() { Node child = first; if (child != null) { removeChild(child); } return child; } /** * @return A Node that is the head of the list of children. */ public Node removeChildren() { Node children = first; for (Node child = first; child != null; child = child.getNext()) { child.parent = null; } first = null; last = null; return children; } /** * Removes all children from this node and isolates the children from each * other. */ public void detachChildren() { for (Node child = first; child != null; ) { Node nextChild = child.getNext(); child.parent = null; child.next = null; child = nextChild; } first = null; last = null; } public Node removeChildAfter(Node prev) { Preconditions.checkArgument(prev.parent == this, "prev is not a child of this node."); Preconditions.checkArgument(prev.next != null, "no next sibling."); Node child = prev.next; prev.next = child.next; if (child == last) last = prev; child.next = null; child.parent = null; return child; } /** * @return A detached clone of the Node, specifically excluding its * children. */ public Node cloneNode() { Node result; try { result = (Node) super.clone(); result.next = null; result.first = null; result.last = null; result.parent = null; } catch (CloneNotSupportedException e) { throw

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> this is a synthetic block that should not be considered * a real source block. */ public void setIsSyntheticBlock(boolean val) { putBooleanProp(SYNTHETIC_BLOCK_PROP, val); } /** * Returns whether this is a synthetic block that should not be considered * a real source block. */ public boolean isSyntheticBlock() { return getBooleanProp(SYNTHETIC_BLOCK_PROP); } /** * Sets whether this is a synthetic block that should not be considered * a real source block. */ public void setWasEmptyNode(boolean val) { putBooleanProp(EMPTY_BLOCK, val); } /** * Returns whether this is a synthetic block that should not be considered * a real source block. */ public boolean wasEmptyNode() { return getBooleanProp(EMPTY_BLOCK); } /** * Marks this function or constructor call node as having no side effects. * This property is only meaningful for {@link Token#CALL} and * {@link Token#NEW} nodes. */ public void setIsNoSideEffectsCall() { Preconditions.checkArgument( getType() == Token.CALL || getType() == Token.NEW, "setIsNoSideEffectsCall only supports CALL and NEW nodes, got " + Token.name(getType())); putBooleanProp(NO_SIDE_EFFECTS_CALL, true); } /** * Returns true if this node is a function or constructor call that * has no side effects. */ public boolean isNoSideEffectsCall() { return getBooleanProp(NO_SIDE_EFFECTS_CALL); } /** * This should only be called for STRING nodes created in object lits. */ public boolean isQuotedString() { return false; } /** * This should only be called for STRING nodes created in object lits. */ public void setQuotedString() { Kit.codeBug(); } }

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> InstanceObjectType(JSTypeRegistry registry, FunctionType constructor, boolean isNativeType) { super(registry, null, null, isNativeType); Preconditions.checkNotNull(constructor); this.constructor = constructor; } @Override public String getName() { return getConstructor().getName(); } @Override public boolean hasName() { return getConstructor().hasName(); } @Override public ObjectType getImplicitPrototype() { return getConstructor().getPrototype(); } @Override public FunctionType getConstructor() { return constructor; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { ObjectType proto = getImplicitPrototype(); if (proto != null && proto.hasOwnDeclaredProperty(name)) { return false; } return super.defineProperty(name, type, inferred, inExterns); } @Override public String toString() { return constructor.getName(); } @Override boolean isTheObjectType() { return getConstructor().isNative() && "Object".equals(getName()); } @Override public boolean isInstanceType() { return true; } @Override public boolean isArrayType() { return getConstructor().isNative() && "Array".equals(getName()); } @Override public boolean isStringObjectType() { return getConstructor().isNative() && "String".equals(getName()); } @Override public boolean isBooleanObjectType() { return getConstructor().isNative() && "Boolean".equals(getName()); } @Override public boolean isNumberObjectType() { return getConstructor().isNative() && "Number".equals(getName()); } @Override public boolean isDateType() { return getConstructor().isNative() && "Date".equals(getName()); } @Override public boolean isRegexpType() { return getConstructor().isNative() && "RegExp".equals(getName()); } @Override boolean isNominalType() { return hasName(); } @Override public boolean isSubtype(JSType that) { if (super.isSubtype(that)) { return true; } List<ObjectType> thisInterfaces = getConstructor().getImplementedInterfaces(); if (thisInterfaces != null) { List<ObjectType> thatInterfaces

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>(aliasVar)); (new NodeTraversal(compiler, collector)).traverseAtScope(scope); ReferenceCollection aliasRefs = collector.getReferenceCollection(aliasVar); if (aliasRefs.isWellDefined() && aliasRefs.firstReferenceIsAssigningDeclaration() && aliasRefs.isAssignedOnce()) { // The alias is well-formed, so do the inlining now. int size = aliasRefs.references.size(); Set<Node> newNodes = Sets.newHashSetWithExpectedSize(size - 1); for (int i = 1; i < size; i++) { ReferenceCollectingCallback.Reference aliasRef = aliasRefs.references.get(i); Node newNode = alias.node.cloneTree(); aliasRef.getParent().replaceChild(aliasRef.getNameNode(), newNode); newNodes.add(newNode); } // just set the original alias to null. aliasParent.replaceChild(alias.node, new Node(Token.NULL)); compiler.reportCodeChange(); // Inlining the variable may have introduced new references // to descendents of {@code name}. So those need to be collected now. namespace.scanNewNodes(alias.scope, newNodes); return true; } } return false; } /** * Runs through all namespaces (prefixes of classes and enums), and checks if * any of them have been used in an unsafe way. */ private void checkNamespaces() { for (Name name : nameMap.values()) { if (name.isNamespace() && name.refs != null && (name.aliasingGets > 0 || name.localSets + name.globalSets > 1)) { boolean initialized = name.declaration != null; for (Ref ref : name.refs) { if (ref.type == Ref.Type.SET_FROM_GLOBAL || ref.type == Ref.Type.SET_FROM_LOCAL) { if (initialized) { warnAboutNamespaceRedefinition(name, ref); } initialized = true; } else if (ref.type == Ref.Type.ALIASING_GET) { warnAboutNamespaceAliasing(name, ref); } } } } } /** * Reports a warning because a namespace was aliased. * * @param nameObj

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>). These are // called TWIN references, because they show up twice in the // reference list. Only collapse the set, not the alias. if (!NodeUtil.isObjectLitKey(r.node, rParent) && (r.getTwin() == null || r.isSet())) { flattenNameRef(alias, r.node, rParent, originalName); } } } // Flatten all occurrences of a name as a prefix of its subnames. For // example, if {@code n} corresponds to the name "a.b", then "a.b" will be // replaced with "a$b" in all occurrences of "a.b.c", "a.b.c.d", etc. if (n.props != null) { for (Name p : n.props) { flattenPrefixes(alias, p, 1); } } } /** * Flattens all occurrences of a name as a prefix of subnames beginning * with a particular subname. * * @param n A global property name (e.g. "a.b.c.d") * @param alias A flattened prefix name (e.g. "a$b") * @param depth The difference in depth between the property name and * the prefix name (e.g. 2) */ private void flattenPrefixes(String alias, Name n, int depth) { // Only flatten the prefix of a name declaration if the name being // initialized is fully qualified (i.e. not an object literal key). String originalName = n.fullName(); if (n.declaration != null && n.declaration.node != null && n.declaration.node.getType() == Token.GETPROP) { flattenNameRefAtDepth(alias, n.declaration.node, depth, originalName); } if (n.refs != null) { for (Ref r : n.refs) { // References inside a complex assign (a = x.y = 0) // have twins. We should only flatten one of the twins. if (r.getTwin() == null || r.isSet()) { flattenNameRefAtDepth(alias, r.node, depth, originalName); } } } if (n.props

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>(); } /** * Collapses definitions of the collapsible properties of a global name. * Recurses on subnames that also represent JavaScript objects with * collapsible properties. * * @param n A node representing a global name * @param alias The flattened name for {@code n} */ private void collapseDeclarationOfNameAndDescendants(Name n, String alias) { boolean canCollapseChildNames = n.canCollapseUnannotatedChildNames(); // Handle this name first so that nested object literals get unrolled. if (n.canCollapse() && canCollapseChildNames) { updateObjLitOrFunctionDeclaration(n, alias); } if (n.props != null) { for (Name p : n.props) { // Recurse first so that saved node ancestries are intact when needed. collapseDeclarationOfNameAndDescendants(p, alias + '$' + p.name); if (!p.inExterns && canCollapseChildNames && p.declaration != null && p.declaration.node != null && p.declaration.node.getParent() != null && p.declaration.node.getParent().getType() == Token.ASSIGN) { updateSimpleDeclaration(alias + '$' + p.name, p.declaration); } } } } /** * Updates the initial assignment to a collapsible property at global scope * by changing it to a variable declaration (e.g. a.b = 1 -> var a$b = 1). * The property's value may either be a primitive or an object literal or * function whose properties aren't collapsible. * * @param alias The flattened property name (e.g. "a$b") * @param ref An object containing information about the assignment getting * updated */ private void updateSimpleDeclaration(String alias, Ref ref) { Node rvalue = ref.node.getNext(); Node parent = ref.node.getParent(); Node gramps = parent.getParent(); Node greatGramps = gramps.getParent(); Node greatGreatGramps = greatGramps.getParent(); // Create the new alias node. Node nameNode = NodeUtil.newName(alias, gramps.getFirstChild(), alias.replace("$", "."));

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> if (ref.node.getLastChild().getBooleanProp(Node.IS_CONSTANT_NAME)) { nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true); } if (gramps.getType() == Token.EXPR_RESULT) { // BEFORE: a.b.c = ...; // exprstmt // assign // getprop // getprop // name a // string b // string c // NODE // AFTER: var a$b$c = ...; // var // name a$b$c // NODE // Remove the rvalue (NODE). parent.removeChild(rvalue); nameNode.addChildToFront(rvalue); Node varNode = new Node(Token.VAR, nameNode); greatGramps.replaceChild(gramps, varNode); } else { // This must be a complex assignment. Preconditions.checkNotNull(ref.getTwin()); // BEFORE: // ... (x.y = 3); // // AFTER: // var x$y; // ... (x$y = 3); Node current = gramps; Node currentParent = gramps.getParent(); for (; currentParent.getType() != Token.SCRIPT && currentParent.getType() != Token.BLOCK; current = currentParent, currentParent = currentParent.getParent()) {} // Create a stub variable declaration right // before the current statement. Node stubVar = new Node(Token.VAR, nameNode.cloneTree()); currentParent.addChildBefore(stubVar, current); parent.replaceChild(ref.node, nameNode); } compiler.reportCodeChange(); } /** * Updates the first initialization (a.k.a "declaration") of a global name. * This involves flattening the global name (if it's not just a global * variable name already), collapsing object literal keys into global * variables, declaring stub global variables for properties added later * in a local scope, and eliminating the global name entirely (if possible). * * @param n An object representing a global name (e.g. "a", "a.b.c") * @param alias The flattened name for {@code n} (

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>e.g. "a", "a$b$c") */ private void updateObjLitOrFunctionDeclaration(Name n, String alias) { switch (n.declaration.node.getParent().getType()) { case Token.ASSIGN: updateObjLitOrFunctionDeclarationAtAssignNode(n, alias); break; case Token.VAR: updateObjLitOrFunctionDeclarationAtVarNode(n); break; case Token.FUNCTION: updateFunctionDeclarationAtFunctionNode(n); break; } } /** * Updates the first initialization (a.k.a "declaration") of a global name * that occurs at an ASSIGN node. See comment for * {@link #updateObjLitOrFunctionDeclaration}. * * @param n An object representing a global name (e.g. "a", "a.b.c") * @param alias The flattened name for {@code n} (e.g. "a", "a$b$c") */ private void updateObjLitOrFunctionDeclarationAtAssignNode( Name n, String alias) { // NOTE: It's important that we don't add additional nodes // (e.g. a var node before the exprstmt) because the exprstmt might be // the child of an if statement that's not inside a block). Ref ref = n.declaration; Node rvalue = ref.node.getNext(); Node varNode = new Node(Token.VAR); Node varParent = ref.node.getAncestor(3); Node gramps = ref.node.getAncestor(2); boolean isObjLit = rvalue.getType() == Token.OBJECTLIT; if (isObjLit && n.canEliminate()) { // Eliminate the object literal altogether. varParent.replaceChild(gramps, varNode); ref.node = null; } else { if (rvalue.getType() == Token.FUNCTION) { checkForHosedThisReferences(rvalue, n.docInfo, n); } ref.node.getParent().removeChild(rvalue); Node nameNode = NodeUtil.newName( alias, ref.node.getAncestor(2), n.fullName()); if (ref.node.getLastChild().getBooleanProp(Node.IS_CONSTANT_NAME)) {

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true); } varNode.addChildToBack(nameNode); nameNode.addChildToFront(rvalue); varParent.replaceChild(gramps, varNode); // Update the node ancestry stored in the reference. ref.node = nameNode; } if (isObjLit) { boolean discardKeys = n.aliasingGets == 0; declareVarsForObjLitValues( alias, rvalue, varNode, varParent.getChildBefore(varNode), varParent, discardKeys); } addStubsForUndeclaredProperties(n, alias, varParent, varNode); if (!varNode.hasChildren()) { varParent.removeChild(varNode); } compiler.reportCodeChange(); } /** * Warns about any references to "this" in the given FUNCTION. The function * is getting collapsed, so the references will change. */ private void checkForHosedThisReferences(Node function, JSDocInfo docInfo, final Name name) { // A function is getting collapsed. Make sure that if it refers to // "this", it must be a constructor or documented with @this. if (docInfo == null || (!docInfo.isConstructor() && !docInfo.hasThisType())) { NodeTraversal.traverse(compiler, function.getLastChild(), new NodeTraversal.AbstractShallowCallback() { public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.THIS) { compiler.report( JSError.make(name.declaration.sourceName, n, UNSAFE_THIS, name.fullName())); } } }); } } /** * Updates the first initialization (a.k.a "declaration") of a global name * that occurs at a VAR node. See comment for * {@link #updateObjLitOrFunctionDeclaration}. * * @param n An object representing a global name (e.g. "a") */ private void updateObjLitOrFunctionDeclarationAtVarNode(Name n) { Ref ref = n.declaration; String name = ref.node.getString(); Node rvalue = ref.node.getFirstChild(); Node varNode =

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> ref.node.getParent(); Node gramps = varNode.getParent(); boolean isObjLit = rvalue.getType() == Token.OBJECTLIT; int numChanges = 0; if (isObjLit) { boolean discardKeys = n.aliasingGets == 0; numChanges += declareVarsForObjLitValues( name, rvalue, varNode, gramps.getChildBefore(varNode), gramps, discardKeys); } numChanges += addStubsForUndeclaredProperties(n, name, gramps, varNode); if (isObjLit && n.canEliminate()) { varNode.removeChild(ref.node); if (!varNode.hasChildren()) { gramps.removeChild(varNode); } numChanges++; // Clear out the object reference, since we've eliminated it from the // parse tree. ref.node = null; } if (numChanges > 0) { compiler.reportCodeChange(); } } /** * Updates the first initialization (a.k.a "declaration") of a global name * that occurs at a FUNCTION node. See comment for * {@link #updateObjLitOrFunctionDeclaration}. * * @param n An object representing a global name (e.g. "a") */ private void updateFunctionDeclarationAtFunctionNode(Name n) { Ref ref = n.declaration; String fnName = ref.node.getString(); addStubsForUndeclaredProperties( n, fnName, ref.node.getAncestor(2), ref.node.getParent()); } /** * Declares global variables to serve as aliases for the values in an object * literal, optionally removing all of the object literal's keys and values. * * @param alias The object literal's flattened name (e.g. "a$b$c") * @param objlit The OBJLIT node * @param varNode The VAR node to which new global variables should be added * as children * @param nameToAddAfter The child of {@code varNode} after which new * variables should be added (may be null) * @param varParent {@code varNode}'s parent * @param discardKeys Whether to eliminate the object literal's keys after *

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> newVar; if (isJsIdentifier) { // Update the global name's node ancestry if it hasn't already been // done. (Duplicate keys in an object literal can bring us here twice // for the same global name.) Name p = nameMap.get(qName); if (p != null) { if (!discardKeys) { Ref newAlias = p.declaration.cloneAndReclassify(Ref.Type.ALIASING_GET); newAlias.node = refNode; p.addRef(newAlias); } p.declaration.node = nameNode; if (value.getType() == Token.FUNCTION) { checkForHosedThisReferences(value, value.getJSDocInfo(), p); } } } numVars++; } return numVars; } /** * Adds global variable "stubs" for any properties of a global name that are * only set in a local scope or read but never set. * * @param n An object representing a global name (e.g. "a", "a.b.c") * @param alias The flattened name of the object whose properties we are * adding stubs for (e.g. "a$b$c") * @param parent The node to which new global variables should be added * as children * @param addAfter The child of after which new * variables should be added (may be null) * @return The number of variables added */ private int addStubsForUndeclaredProperties( Name n, String alias, Node parent, Node addAfter) { Preconditions.checkArgument(NodeUtil.isStatementBlock(parent)); int numStubs = 0; if (n.props != null) { for (Name p : n.props) { if (p.needsToBeStubbed()) { String propAlias = alias + '$' + p.name; Node nameNode = Node.newString(Token.NAME, propAlias); Node newVar = new Node(Token.VAR, nameNode); if (addAfter == null) { parent.addChildToFront(newVar); } else { parent.addChildAfter(newVar, addAfter); addAfter = newVar; } numStubs++;

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> the type of {@code this} is unknown. * @param templateTypeName The template type name or {@code null}. */ public FunctionType(JSTypeRegistry registry, String name, Node source, Node parameters, JSType returnType, ObjectType typeOfThis, String templateTypeName) { this(registry, name, source, parameters, returnType, typeOfThis, templateTypeName, false, false); } /** Creates an instance for a function that might be a constructor. */ FunctionType(JSTypeRegistry registry, String name, Node source, Node parameters, JSType returnType, ObjectType typeOfThis, String templateTypeName, boolean isConstructor, boolean nativeType) { super(registry, name, registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE), nativeType); Preconditions.checkArgument(source == null || Token.FUNCTION == source.getType()); this.source = source; this.kind = isConstructor ? Kind.CONSTRUCTOR : Kind.ORDINARY; if (isConstructor) { this.typeOfThis = typeOfThis != null && typeOfThis.isNoObjectType() ? typeOfThis : new InstanceObjectType(registry, this, nativeType); } else { this.typeOfThis = typeOfThis != null ? typeOfThis : registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); } // The call type should be set up last because we are calling getReturnType, // which may be overloaded and depend on other properties being set. this.call = new ArrowType(registry, parameters, (returnType == null ? getReturnType() : returnType)); this.templateTypeName = templateTypeName; } /** Creates an instance for a function that is an interface. */ FunctionType(JSTypeRegistry registry, String name, Node source) { super(registry, name, registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE)); Preconditions.checkArgument(source == null || Token.FUNCTION == source.getType()); Preconditions.checkArgument(name != null); this.source = source; this.call = null; this.kind = Kind.INTERFACE; this.typeOfThis = new InstanceObjectType(registry, this); } @Override public boolean isInstanceType() { // The universal constructor is its own instance, bizarrely. return

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS> if (functionInstance.equals(this)) { return that; } return registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE); } return super.getGreatestSubtype(that); } /** * Given a constructor or an interface type, get its superclass constructor * or {@code null} if none exists. */ public FunctionType getSuperClassConstructor() { Preconditions.checkArgument(isConstructor() || isInterface()); ObjectType maybeSuperInstanceType = getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return null; } return maybeSuperInstanceType.getConstructor(); } /** * Given a constructor or an interface type, find out whether the unknown * type is a supertype of the current type. */ public boolean hasUnknownSupertype() { Preconditions.checkArgument(isConstructor() || isInterface()); Preconditions.checkArgument(!this.isUnknownType()); // Potential infinite loop if our type system messes up or someone defines // a bad type. Otherwise the loop should always end. FunctionType ctor = this; while (true) { ObjectType maybeSuperInstanceType = ctor.getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return false; } if (maybeSuperInstanceType.isUnknownType()) { return true; } ctor = maybeSuperInstanceType.getConstructor(); if (ctor == null) { return false; } Preconditions.checkState(ctor.isConstructor() || ctor.isInterface()); } } /** * Given a constructor or an interface type and a property, finds the * top-most superclass that has the property defined (including this * constructor). */ public JSType getTopMostDefiningType(String propertyName) { Preconditions.checkState(isConstructor() || isInterface()); Preconditions.checkArgument(getPrototype().hasProperty(propertyName)); FunctionType ctor = this; JSType topInstanceType; do { topInstanceType = ctor.getInstanceType(); ctor = ctor.getSuperClassConstructor(); } while (ctor != null && ctor.getPrototype().hasProperty(propertyName)); return topInstanceType; } /** * Two function types are equal if their signatures match. Since they don't * have signatures,

Closure, 106

<FILEB>
<CHANGES>
Preconditions.checkNotNull(declaration);
if (declaration.getTwin()!= null) {
return false;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> return false; } } } return true; } boolean canCollapse() { return !inExterns && (isClassOrEnum || (parent == null || parent.canCollapseUnannotatedChildNames()) && (globalSets > 0 || localSets > 0)); } boolean canCollapseUnannotatedChildNames() { if (type == Type.OTHER || globalSets != 1 || localSets != 0) { return false; } // Don't try to collapse if the one global set is a twin reference. // We could theoretically handle this case in CollapseProperties, but // it's probably not worth the effort. <CHANGES> <CHANGEE> if (isClassOrEnum) { return true; } return (type == Type.FUNCTION || aliasingGets == 0) && (parent == null || parent.canCollapseUnannotatedChildNames()); } boolean needsToBeStubbed() { return globalSets == 0 && localSets > 0; } void setIsClassOrEnum() { isClassOrEnum = true; for (Name ancestor = parent; ancestor != null; <FILEE> <FILEB> } /** * Adds a name declaration to the current marker. */ public void markName(String name, int lineno, int charno) { if (currentMarker != null) { currentMarker.name = new JSDocInfo.StringPosition(); currentMarker.name.setItem(name); currentMarker.name.setPositionInformation(lineno, charno, lineno, charno + name.length()); } } /** * Records a block-level description. * * @return {@code true} if the description was recorded. */ public boolean recordBlockDescription(String description) { <CHANGES> if (parseDocumentation) { <CHANGEE> populated = true; <CHANGES> } <CHANGEE> return currentInfo.documentBlock(description); } /** * Records a visibility. * * @return {@code true} if the visibility was recorded and {@code false} * if it was already defined */ public boolean recordVisibility(Visibility visibility) { if (currentInfo.getVisibility() == null) { populated = true; currentInfo.setVisibility(visibility); <FILEE> <SCANS>.typeOfThis.isSubtype(other.typeOfThis)) && this.call.isSubtype(other.call); } if (that instanceof UnionType) { UnionType union = (UnionType) that; for (JSType element : union.alternates) { if (this.isSubtype(element)) { return true; } } } return getNativeType(JSTypeNative.FUNCTION_PROTOTYPE).isSubtype(that); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseFunctionType(this); } /** * Gets the type of instance of this function. * @throws IllegalStateException if this function is not a constructor * (see {@link #isConstructor()}). */ public ObjectType getInstanceType() { Preconditions.checkState(hasInstanceType()); return typeOfThis; } /** Sets the instance type. This should only be used for special native types. */ void setInstanceType(ObjectType instanceType) { typeOfThis = instanceType; } /** * Returns whether this function type has an instance type. */ public boolean hasInstanceType() { return isConstructor() || isInterface(); } /** * Gets the type of {@code this} in this function. */ public ObjectType getTypeOfThis() { return typeOfThis.isNoObjectType() ? registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE) : typeOfThis; } /** * Gets the source node. */ public Node getSource() { return source; } /** * Sets the source node. */ public void setSource(Node source) { this.source = source; } /** Adds a type to the list of subtypes for this type. */ private void addSubType(FunctionType subType) { if (subTypes == null) { subTypes = Lists.newArrayList(); } subTypes.add(subType); } /** * Returns a list of types that are subtypes of this type. This is only valid * for constructor functions, and may be null. This allows a downward * traversal of the subtype graph. */ public List<FunctionType> getSubTypes() { return subTypes; } @Override public boolean hasCachedValues() {